https://kotlinlang.org logo
#feed
Title
# feed
j

James Richardson

01/02/2020, 6:35 PM
There are known issues with testing singletons and mocking static methods. It's a pattern to be approached with care.
👍 3
a

Adam Hurwitz

01/02/2020, 8:58 PM
Thanks @James Richardson! Another dev. echoed the feedback on
static
methods in my article post thread above. I'll take a look at avoiding this library method from being called to begin with. I will look into the
Singleton
point more. I see there is one thread here on the topic: https://stackoverflow.com/questions/8256989/singleton-and-unit-testing
b

Ben Abramovitch

01/02/2020, 9:22 PM
As long as you have a way to "reset" the singleton they should be testable. I haven't had any problems. You should be able to do that with DI where you reset it in the @Before or @After o some other destructive method. It is an extra step you need to be aware of and always deal with though, otherwise tests may randomly fail from remembered state.
a

Adam Hurwitz

01/02/2020, 9:40 PM
Thanks! Good to know @Ben Abramovitch, as I do have a test extension that resets the Repository mock after the tests.
j

James Richardson

01/02/2020, 11:04 PM
JUnit creates an instance of the test class while running each test. This is a great design choice. It means that everything in your test will have fresh state. however, static state (and I include singletons in this) is shared across the whole JVM (ok, classloaders can do some stuff, but in general theres only one copy of this state) - resetting it is error prone - you may not know what state needs to be reset, and/or you may do it wrong - it is also conceptually problematic - a test is not supposed to know about the implementation of the classes it tests, only the observable effects.
in addition, having shared static state in a system means that testing cannot be done in parallel in the same JVM, else the tests will interfere with each other. its a way that the test system is telling you that there may be an issue.
☝️ 2
b

Ben Abramovitch

01/02/2020, 11:06 PM
When I was saying reset, I didn't mean go singletonVariable.value = null. I meant a method to completely wipe the singleton from existence so it can create a new one. In the tear down destroying the instance doesn't really go against the test knowing about state
E.G In Koin you can do this in @After
Copy code
unloadKoinModules()
For each test which would then return a new single instance the next time the test is run, but it might do this automatically as well (I'm new to koin testing) . I imagine that's what the stopKoin call actually does in a test.
j

James Richardson

01/02/2020, 11:07 PM
it is a shame that the android docs talk about such design patterns - Singletons, static state, Service Locators and nulls are generally avoided wherever possible in testable, reliable code
once you start to have static state in a codebase it is terribly difficult to get rid of it - one singleton can reference another and so on...
d

Daniel

01/02/2020, 11:31 PM
The fun of debugging randomly failing ui (or unit) tests is worth it though.. (sarcasm)... its just a fact, someone will at some point forget to reset static state. And then you have tests failing because they are ordered in a certain way. For example you have tests failing in ci but they work on your machine on first glance. Fun!
a

Adam Hurwitz

01/03/2020, 3:31 AM
@James Richardson, Love the constructive feedback above! To conclude, would implementing Dagger2 to create the Repository and Database instances be one proposed refactor to avoid the issues with using Singletons above?
9 Views