-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mocked time #60
Comments
I agree, that would be a great feature to have. One problem that I'm currently not sure is possible to solve right now is detecting when time can be "pushed forward". This should be done only when all threads of execution have suspended (either on |
A project with similar goals (though no longer developed / maintained) is https://github.com/devexperts/time-test, but probably doesn't work with Loom |
IMHO this can only work if getting current time, and waiting for somehting comes together, e.g.
In my opinion, it shouldn't be necessary to track all other threads suspensions state, as long as the clock is monotonically increasing, because other threads can't make more assumptions. And if something crashes because the time advanced, well, that's exactly what a test should figure out. On the other hand, all (testable) access to the time/wait must then use this clock, maybe in some scoped value? |
Yes, we can make this available via a scoped value, but what would the |
Idea is to write tests assuming execution of non-blocking code takes zero time. Which is true in most practical cases involving |
I think it depends on the test scope. But if
|
Ah, good to share some examples :) Something that I had in mind: val i = AtomicInteger(0)
fork {
i.getAndAdd(1)
}
sleep(10.seconds)
assert(i.get() == 1) In (almost ;) ) every "normal" execution that test would pass. But if sleeps don't sleep, it would fail. |
Isn't that good rather than bad? :-) |
Yes, you're right in principle, but then ... what are the usual cases for having One non-artificial example that comes to my mind is sending pings over a web socket: fork {
forever {
ws.send(Ping())
sleep(1.second)
}
}
ws.send(msgsToSendChannel.receive()) with the sleep-doesn't-sleep, the test might end up sending an infinite stream of pings, and no messages altogether. Or vice versa. |
I see two alternatives in your example
In the end it looks like, multiple clock implementations can be discussed, depending on the way of testing methods. |
Cases I've encountered (and written tests for!) are:
Additionally, from my experience of writing emulated time tests (for Future though, it is much easier): edit: here is some inspiration: https://gist.github.com/scf37/4071839f25e197e38e4b070cfbed977b |
@scf37 this sounds more or less like mocking of the clock for me, so that the test itself is capable of releasing waits. This is a perfect use case for complicated things, which involves multiple threads. In my small unit test thinking I would like to get rid of threads all together to get a deterministic behaviour. We can run a function, which itself calls wait/waitFor and has some stopping kriteria (e.g. when simulated time is out or some or some explicit behavior). Consequently this leads to multiple clock implementations. |
Provided Mock does exactly that - it performs linearization by adding chunks of code to single queue executed by test. Unfortunately there is no API in Loom to access such "chunks" (AKA coroutines/continuations) therefore I don't know how to implement deterministic tests outside of Futures. Still, emulated delays are much better than nothing. |
Add
delay
andnow
functions. Add test runtime with emulated clock to test code with delays without spending actual time on delays.Would be invaluable for testing asynchronous code, not sure is this even possible with current Loom design but might be worth a try.
There is similar feature in cats-effect, separate effect evaluator with emulated time: https://typelevel.org/cats-effect/docs/core/test-runtime#mocking-time
The text was updated successfully, but these errors were encountered: