Given this code:
// Subject.kt
open class Subject(var x: Int) {
constructor(): this(42) {
println("made it")
}
fun doit() {
x += 1
println("did it: $x")
}
}
// Tests.kt
import org.junit.jupiter.api.Test
import org.mockito.Mockito
class Tests {
@Test
fun makeit() {
val mock = Mockito.mock(Subject::class.java)
val details = Mockito.mockingDetails(mock)
println("Is mock: ${details.isMock}")
println("Is spy: ${details.isSpy}")
mock.doit()
mock.doit()
}
}
When makeit
is run, the output is:
Is mock: true
Is spy: false
did it: 1
did it: 2
This seems to indicate that some instance of the subject is being created but bypassing potentially critical constructor logic. This is consistent with a "partial mock", but the code has done nothing to request such a thing.
I find it surprising this is default behavior since the docs all warn strongly against using partial mocks. I have been unable to find docs that describe when mock()
returns a partial mock, and thus can't figure out how to get a "full mock" from a class.
So:
- When does
Mockito.mock()
create a partial mock? - Can Mockito create a "full mock" for a class? Or just for an interface?
- How does one request a "full mock"?
Poking through the source code and by trial and error testing, I have come to the following conclusions:
open
in Kotlin):when(...).thenCallRealMethod()
.defaultAnswer
set toCALLS_REAL_METHODS
final
methods cannot be overridden => they will be invoked normally, but they will see default values for all member data.So, it seems that all class mocks are partial mocks, but since the default in Java is for methods to be open, they often look like regular mocks. By default, they are effectively regular mocks.
This shows up quickly in Kotlin since methods are
final
by default.Knowing how this works makes dealing with class mocks less frustrating!