A `shared { }` defined at top level, is supposed t...
# opensavvy
d
A
shared { }
defined at top level, is supposed to run once for all specs, or is recreated per spec (I mean class where there are a bunch of tests or suites)?
It seems like it gets initialised only once... so I suppose there's no
beforeSpec { }
concept either? I guess the obvious Prepared solution is declare a top level
val prepareDb = shared { ... }
and then declare
val db by prepareDb
in the tests... the problem is that
prepareDb
can't be depended on by other top levels, leading to redeclaring the db (test container) AND the sql client in every test class... a bit more verbose, but again, this concept of writing everything in the test and not having global state?
c
is supposed to run once for all specs
Yes, if at least one test uses it. If no tests use it, it doesn't run at all
👍🏼 1
val prepareDb = shared { ... }
Please keep the naming separate, prepared & shared values are two very different things! don't confuse yourself You can invoke shared values from prepared values, but not the opposite
d
Which is better than Kotest extensions that when installed globally are run whether needed or not... I often had to make special objects for these cases and not use extensions (especially when test containers aren't used everywhere and you're running a test that doesn't depend on them)...
1
Please keep the naming separate,...
oops I guess that's
val shareDb = ...
?
👍 1
c
The idea is two switch your mindset around; instead of thinking "here are the things all tests need", you need to think in terms of "what does this test needs". When you start writing multiple tests, you'll see that you need some stuff again. At that point, that stuff goes into prepared values. Rince and repeat
d
Oh, but in the refs it says:
Although SharedProvider is conceptually equivalent to PreparedProvider, and can be used to generate multiple Shared instances from the same block in exactly the same way, this is not recommended.
so there's no such thing...?
Re-using something for whole test class (PreparedSpec) w/o repeating the whole definition in each of them, and the tests themselves re-use it...?
c
Sorry, this is referring to binding the same provider multiple times e.g. you can do
Copy code
fun randomInt() = prepared { random.nextInt() }

val int1 by randomInt()
val int2 by randomInt()
this creates two different prepared values with the same init code (they will really have different values when ran), because the "identity" of a prepared value is the variable it is bound to you can do the same with shared values, but IMO it's a bad idea
d
So using them in separate classes is OK then?
👍 1
c
actually you can even write
Copy code
val randomInt = prepared { … }
val int1 by randomInt
val int2 by randomInt
to get multiple prepared values from the same init code
d
Just as long as only one is declared per class. I guess you could specify that in that warning...
c
So using them in separate classes is OK then?
Yes. Since you always have to refer to them explicitly, you can declare them anywhere you want, even at the top level: they can never accidentally impact another test
d
Since you always have to refer to them explicitly
even when using them multiple times in the same class you refer to each one explicitly?
c
yes, there's no other way to use them
Btw if that helps you understand the difference: • prepared values are cached on first use in the test • shared values are cached on first use in the value itself
d
That I understood, but I'm still a bit unclear what could go wrong with
Copy code
val db = shared { … }
val db1 by db
val db2 by db
more than if they were used in separate classes... the only little problem is that there's no way to clean them up really... so in test container's we'd need to rely on ryuk for example...
c
Nothing will go wrong, it's just, it doesn't really make sense
image.png
In those three bullet points, you'll notice that the value must be immutable and side-effect-free. If that's the case, then binding it multiple times makes no sense because they will all get the same value
💡 1
d
Oh... now I get it, thanks!
I think if you put it that simply in the warning in the docs site, it should be better than the long technical-like explanation (although now that I understand the point, I reread it there and it's clear... but initially it wasn't so clear in practical terms.)
d
It's too theoretical, I think the best explanations for end-users are practical explanations or examples that portray the problematic cases.
In those three bullet points, you'll notice that the value must be immutable and side-effect-free. If that's the case, then binding it multiple times makes no sense because they will all get the same value
this is very practical.
c
Can you create an issue with your thoughts on this?
I'm going to have some work this weekend ahah
😅 1
d
Maybe I'll try tomorrow if I remember... I still have a few things to finish up today, and I'm running a bit late...