I'm unsure of how to actually describe this, but if I attempt to memoize something like
val originalOut by memoized<PrintStream>()
...
val originalOut by memoize { System.out }
the test fails to run in intellij, this is what it looks like

Very strange indeed.
However it doesn't seam to happen in memoize but when System.setOut is called.
Here is a minimal reproducer:
object MemoizedStreamSpec : Spek({
describe("System.setOut") {
it("should replace standard output stream") {
val baos = ByteArrayOutputStream()
System.setOut(PrintStream(baos))
print("Hello world")
assertEquals("Hello world", String(baos.toByteArray()))
}
}
})
EDIT: It is only a problem of the IntellIJ plugin. Running the test from gradle pass as expected.
@jcornaz it doesn't work for you without the memoization? That's weird because for me if I leave it as
fun Root.setupStreams() {
val outContent by memoized<ByteArrayOutputStream>()
val errContent by memoized<ByteArrayOutputStream>()
val originalOut = System.out
val originalErr = System.err
// Create new byte stream for each test
beforeEachTest {
System.setOut(PrintStream(outContent))
System.setErr(PrintStream(errContent))
}
afterEachTest {
System.setOut(originalOut)
System.setErr(originalErr)
}
}
it works fine.
I may know what the problem is. When tests are run within IJ a new processed is spawned with stdout and stderr captured; this is used to communicate the test run events to IJ. So my guess is since you are overriding the default print streams - IJ is not receiving any events. Is there a way for you not to write directly to System.out and System.err? Maybe some variables which default to System.out and System.err - but you override them on the tests.
Hmm. well the whole point of my project is to print stuff to console. I'm not sure of another way to test it 馃槩. I guess I could rewrite my function to not use println but instead use a writer and write straight to PrintStream and then mock that in some way, though I tried mocking PrintStream once and it didn't work.
Anyway, if this isn't actually related to spek then we can close it. Sorry for the bother.
I was thinking something like this:
// top level fields
internal var sysout= System.out
internal var syserr = System.err
Instead of using print do sysout.print(...). Then on your tests just override the value of sysout and syserr (probably in setupStreams).
sysout = PrintStream(...)
syserr = PrintStream(...)
Relying on System.out and System.err makes your test very brittle, as anyone can override the value at any given time. Also, a rouge print call from another thread can cause your tests to fail.
Most helpful comment
I was thinking something like this:
Instead of using
printdosysout.print(...). Then on your tests just override the value ofsysoutandsyserr(probably insetupStreams).Relying on
System.outandSystem.errmakes your test very brittle, as anyone can override the value at any given time. Also, a rougeprintcall from another thread can cause your tests to fail.