Remix.run Logo
vocx2tx 8 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.

[0] https://pkg.go.dev/testing/synctest

rtpg 3 hours ago | parent | next [-]

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.

dathinab 8 hours ago | parent | prev | next [-]

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)

WorldMaker 7 hours ago | parent | next [-]

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...

rzzzt 4 hours ago | parent [-]

Java has an interface named InstantSource for this purpose: https://docs.oracle.com/en/java/javase/17/docs/api/java.base...

layer8 3 hours ago | parent [-]

Paradoxically, InstantSource may have a delay. ;)

0x457 7 hours ago | parent | prev [-]

Also, if you do use `now()` in this case you can always do `now() + SomeDistantDuration`

Bratmon 5 hours ago | parent | prev | next [-]

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!

loeg 5 hours ago | parent [-]

No, because prod doesn't have hardcoded cookies baked into it?

AndrewDucker 5 hours ago | parent [-]

If you always test with a date of 1/1/2000 then you don't know that your choice fails in 2039.

vocx2tx 4 hours ago | parent [-]

These fake-time environments let you set the time, so you can test how the code will behave in 2039 without waiting for 13 years. For Go's synctest, 1-1-2000 is just the default initial value for now().

jcul 4 hours ago | parent | prev | next [-]

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.

bombcar 6 hours ago | parent | prev [-]

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?).