I have this class that I need to test. I am thinking it is because I am creating a new instance of the class A:
class A {
fun getName() = "Name"
}
class B {
private a = A()
fun amend(){
return "${a.getName()}-BName"
}
}
Now I want to test class B in BTest.kt
@Test
fun amendTest(){
val b = B()
val cls = mockk<A>()
//everytime getName is called return empty string
every { cls.getName() } returns ""
//call ammend method
val newName = b.amend()
//make sure the getName is called now
verify { cls.getName()}
Truth.assertThat(newName).isEqualTo("-BName")
}
Basically I want to alter the output of A.getName method to return empty string during tests.
CodePudding user response:
When you create val cls = mockk<A>()
, you have made a single instance (cls
) that is a mock of A
, but that doesn't mean that every instance of A
is mocked. The one inside of B
is still a non-mocked instance. As written, B
has a hard dependence on A
which makes it difficult/impossible to test them in isolation. This is a perfect example of one of the benefits of dependency injection. If you defined B
like this:
class B(private val a: A) {
fun amend(): String {
return "${a.getName()}-BName"
}
}
where you inject the implementation of A
, then in your test you could do this:
val cls = mockk<A>()
every { cls.getName() } returns ""
val b = B(cls)
then b
would be using your mocked instance of A
internally. If you have a lot of these dependencies to inject and it gets cumbersome to create them to pass in every time you create B
in your production code, you could always make a companion builder for B
like this
class B(private val a: A, private val c: C, private val d: D) {
fun amend(): String {
return "${a.getName()}-BName"
}
companion object {
fun build(): B {
return B(A(), C(), D())
}
}
}
so in your production code you can call val b = B.build()
but in your unit tests you can call val b = B(aMock, cMock, dMock)
CodePudding user response:
Although it would be advisable that the instance of class A be provided from outside (by constructor or by seter), it is possible do to test with Mockk.
By means of dynamic calls:
val b = spyk(B(), recordPrivateCalls = true)
val cls = mockk<A>()
every { cls. getName() } returns "whatever"
every { b getProperty "a" } returns cls
val result = b.amend()
verify { cls.getName() }
assertEquals("whatever-BName", result)
B must be spy type to capture private properties and to be verified