https://kotlinlang.org logo
Title
a

Andreas Unterweger

11/13/2019, 10:33 AM
hello all, i have a question regarding mockk kotlin mocking framework. how can i mock all instances of an class? i tried:
val ibMock = mockkClass(InstalledBase::class)
every { ibMock.getModelDescriptions() } returns emptyList<ModelDescription>()
but it doesnt work. getModelDescriptions() still returns another list. i have no access to the object instaledbase in my test, but i want that getModelDescriptions() always returns an empty list
s

Stephan Schroeder

11/13/2019, 11:06 AM
you don’t mock the behaviour of a method (on all instances), you only mock the behaviour on the specific (mock) instance.
val ibMock = mockkClass(InstalledBase::class)
every { ibMock.getModelDescriptions() } returns emptyList<ModelDescription>()
effects
ibMock.getModelDescription()
but not
installedbase.getModelDescription()
a

Andreas Unterweger

11/13/2019, 11:07 AM
but how can i mock it on all instances?
s

Stephan Schroeder

11/13/2019, 11:07 AM
you can’t
a

Andreas Unterweger

11/13/2019, 11:07 AM
i thought so....hmmm....this is a limitation...other mocking libs can do this
s

Stephan Schroeder

11/13/2019, 11:07 AM
nope
a

Andreas Unterweger

11/13/2019, 11:08 AM
so no solution to this one?
s

Stephan Schroeder

11/13/2019, 11:09 AM
not in the way you formulated the question. Your approach is probably mistaken, but it’s hard to fix your approach without knowing more about the original problem you’re trying to solve. It’s strange that
installedbase
is a normal (non-mocked) object. You probably need to be able to replace
installedbase
with a mocked object (within the context of the unit-test).
a

Andreas Unterweger

11/13/2019, 11:24 AM
its a loader implementation which returns a list of installedbases. an ex should be thrown when model descs is empty in one of them. so no access to the creation of the instBase. but i changed the test now and it works. still this remains a limitation of mockk. in jmockit this was possible with a MockUp. whatsoever thank you very much for your quick replies
s

Stephan Schroeder

11/13/2019, 12:03 PM
if there is no way to do it in mockk it’s probably a code smell hinting at that you don’t use enough dependency injection in your code 😉 (because as soon as you have dependency injection you can inject mocks instead of runtime instances into the code to be tested)
m

Mike

11/13/2019, 1:04 PM
Just read docs on JMockit. It's written intentionally to be different from other mocking frameworks. It mocks the class rather than the instances based on what I skimmed... Not sure how it accomplishes it, but... I agree with Stephan's assessment that it's not a weakness of MockK. It's a design difference between how JMockit allows you to test and the way MockK does. I've only worked with mocking frameworks like MockK, and use injection so there's more isolation of implementation from consumer. Design choices...
a

Andreas Unterweger

11/14/2019, 10:14 AM
hello, to get back to this. with help from mockk guys on github:
internal class ObjTest : FreeSpec({

        "obj" {

            mockkConstructor(Obj::class)

            every { anyConstructed<Obj>().i } returns 4

            ObjProvider.obj().i shouldBe 4
        }
})

data class Obj(val i : Int = 1)

object ObjProvider {

    fun obj() = Obj()
}