Comment by vocx2tx
21 hours ago
But still a kludge. Better: use something equivalent to Go's testing/synctest[0] package, which lets you write tests that run in a bubble where time is fixed and deterministic.
21 hours ago
But still a kludge. Better: use something equivalent to Go's testing/synctest[0] package, which lets you write tests that run in a bubble where time is fixed and deterministic.
I’ve used freezetime (Python) a decent amount and have experienced some very very very funny flakes due to it.
- Sometimes your test code expects time to be moving forward
- sometimes your code might store classes into a hashmap for caching, and the cache might be built before the freeze time class override kicks in
- sometimes it happens after you have patched the classes and now your cache is weirdly poisoned
- sometimes some serialization code really cares about the exact class used
- sometimes test code acts really weird if time stops moving forward (when people use freezetime frozen=true). Selenium timeouts never clearing was funny
- sometimes your code gets a hold of the unpatched date clsss through silliness but only in one spot
Fun times.
The nicest thing is being able to just pass in a “now” parameter in things that care about time.
in general
- generating test data in a realistic way is often better then hard coding it (also makes it easier to add prop testing or similar)
- make the current time an input to you functions (i.e. the whole old prefer pure functions discussion). This isn't just making things more testable it also can matter to make sure: 1. one unit of logic sees the same time 2. avoid unneeded calls to `now()` (only rarely matters, but can matter)
Similarly, I like .NET's TimeProvider abstraction [1]. You pass a TimeProvider to your functions. At runtime you can provide the default TimeProvider.System. When testing FakeTimeProvider has a lot of handy tools to do deterministic testing.
One of the further benefits of .NET's TimeProvider is that it can also be provided to low level async methods like `await Task.Delay(time, timeProvider, cancellationToken)` which also increases the testability of general asynchronous code in a deterministic sandbox once you learn to pass TimeProvider to even low level calls that take an optional one.
[1] https://learn.microsoft.com/en-us/dotnet/standard/datetime/t...
Java has an interface named InstantSource for this purpose: https://docs.oracle.com/en/java/javase/17/docs/api/java.base...
1 reply →
Also, if you do use `now()` in this case you can always do `now() + SomeDistantDuration`
Doesn't that just turn bugs in test in n years into bugs in prod in n years?
That seems like a downgrade to me!
No, because prod doesn't have hardcoded cookies baked into it?
If you always test with a date of 1/1/2000 then you don't know that your choice fails in 2039.
1 reply →
Ruby's timecop is great for those test scenarios https://github.com/travisjeffery/timecop
This can cause other types of bugs to go unnoticed, such as leap year fun (if you handle 100 years, did you handle the 400th year?).
libfaketime is cool for testing this kind of thing too.
Not as convenient for unit tests cause you have to run the test with LD_PRELOAD.
Found this one for rust: https://github.com/museun/mock_instant
[dead]