<@UFGCACPE0> If there's a class that I need to ini...
# opensavvy
d
@CLOVIS If there's a class that I need to initialise with different implementations (to Fake getting an rss feed and then an updated version of it later), currently I'm using two prepared's one initialised with an RssExtractor with the first version of the feeds and then another one with the updated versions of those feeds, then I need to remember to call the right implementation (which luckily doen't have any state... apart from what it saves to the db which is what I'm asserting against). Is that the "best practice" in this case? Without Prepared, I would have just reinitialised my importer with a new instance... or provided it with a
var
to modify during the test
I figured it out... I just provided a TestClock instance and an ExtractorFake instance to one subject, and they contained a mutable var to change the state... another big โž• for Prepared to force a person into writing better tests. I did do what I said for a bunch of tests but I do admit I wasn't consistent enough w/o Prepared "forcing me" into finding better solutions than global state.
c
Ah, you're discovering the next pattern!
Copy code
interface Dep
class Impl1 : Dep
class Impl2 : Dep

class SystemYouWantToTest(val dep: Dep)

val impl1 by prepared { Impl1() }
val impl2 by prepared { Impl2() }

fun systemTests(system: Prepared<SystemYouWantToTest>) = suite("Test the system you want to test") {
    โ€ฆ
}

suite("All your tests") {
    val deps: List<Prepared<Dep>> = listOf(impl1, impl2)

    for (dep in deps) {
        val system by prepared { SystemYouWanToTest(dep()) }

        systemTests(system)
    }
}
This can be simplified further if you use the
paramaterize
extension module (thanks to #C06083PAKEK!)
Also, do note that the
datetime
compat modules have test clocks ready to use
โž• 1
Whenever you want to test multiple initialization strategies, having a function that declares a suite by taking a
Prepared<WhatYouWantToTest>
is really helpful
d
the
datetime
compat modules have test clocks ready to use
All I see is
time
in the reference section... I guess I'd do
prepared { Foo(time.clock) }
?
c
There should be a dedicated page about time management on the website? it's recent though
but yeah
time.clock
d
It doesn't mention this point... I thought it was more like coroutines time control for delay... it didn't occur to me that it could be used as the clock in dependencies...
if you think there's a better way to say it, I accept feedback!
d
Using the virtual time
Often,
time.nowMillis
is insufficient: we want to trigger algorithms at specific dates in time, for example to check that an algorithm behaves correctly even at midnight on New Year's. Prepared offers compatibility modules to generate datetime objects from popular libraries.
Maybe could clarify that it's not just oriented on time but also dates, and that there's a
Clock
instance that's instantiated and can be manipulated in the test... maybe have the first example use a
val foo by prepared { Foo(time.clock) }
, that'll bring out the feature. Maybe this could be renamed as
Manipulating date and time
, to show the difference with the first section that really only has millis to work with, whereas in with the module, one can work on date and time in a consistent way. I think the problem is that nowadays we're overloaded with information on the Internet, and people (including me) tend to skim through information and only really read what's relevant -- so in my case, I quickly went through the code examples missing the implecation that
time.set(...)
must somehow be usable when instatiating our test subject.
c
Thanks, I'll think about it ๐Ÿ™‚
d
Btw, is there a way to initialise the time for all the tests with the datetime compat module?
It's a bit funny looking at 1970...
c
Put it in a prepared value and import it in all your tests ๐Ÿ™‚
d
๐Ÿ˜ตโ€๐Ÿ’ซ
c
as always, reused prepared values > magical global state
d
Yeah, I guess... so I'll have to go back to 1970 for testing ๐Ÿ˜‚
c
I want it to be impossible to break a test without editing something that's referred to in it If you have a global initialization, it's very easy to change it and break many tests ๐Ÿ˜•
โž• 1
you can also just cc
time.set("2024-01-01TOO:OOZ")
at the start of each test if you want, that's fine IMO
d
It's a bit hard to get out of bad habits, "Prepared" = prepare yourself for big changes ๐Ÿ˜‰, at least it's for the good!
c
Do write down any notes you have about this here please: https://gitlab.com/opensavvy/groundwork/prepared/-/issues/72