Reputation: 1423
When switching to Kotlin, static methods are moved into a companion object. However, there is no obvious way to unit test other methods which call these "static method".
In Java, we could use PowerMockito's MockStatic(SomeClass.class) to verify a static method is called in the method under test. PowerMock loses its magic in Kotlin.
For testing, I have create the following classes.
public class DummyJava {
static public Void staticMechod(){
System.out.print("Dummy method is called");
return null;
}
}
class DummyCompanion {
companion object {
fun someCompanionMethod(){
System.out.printf("companion method is called\n")
}
}
}
Now there is a another class which calls the DummyCompanion.someCompanion
public class DummyWrapper {
public void callAStaticMethod(){
DummyJava.staticMechod();
}
public void callCompanionMethod(){
DummyCompanion.Companion.someCompanionMethod();
}
}
To unit test callAStaticMethod()
We used the following
@RunWith(PowerMockRunner.class)
@PrepareForTest({DummyJava.class, DummyCompanion.Companion.class})
public class staticClassTest {
//This case works
@Test
public void testForStaticMethod() {
PowerMockito.mockStatic(DummyJava.class);
DummyWrapper testObject = new DummyWrapper();
Mockito.when(DummyJava.staticMechod()).thenCallRealMethod();
testObject.callAStaticMethod();
PowerMockito.verifyStatic(Dummy.class);
DummyJava.staticMechod();
}
//This case doesn't work. It always passes.
@Test
public void testForCompanionMethod() {
PowerMockito.mockStatic(DummyCompanion.Companion.class);
DummyWrapper testObject = new DummyWrapper();
testObject.callCompanionMethod();
PowerMockito.verifyStatic(DummyCompanion.Companion.class,Mockito.times(1));
DummyCompanion.Companion.someCompanionMethod();
}
My question is how to verify the companion method is called.
Upvotes: 17
Views: 29071
Reputation: 1423
Solution 1 : add a caller function in the calling class
class DummyWrapper {
val foo get() = DummyCompanion.Companion
fun callAStaticMethod() {
foo.staticMethod()
}
fun callCompanionMethod(){
foo.someCompanionMethod();
}
}
In the test class, we can use Mockito to provide a stub for the get()
function and verified it is called.
@Test
fun testCase() {
....
val mockCompanionObj: DummyCompanion.Companion = mock()
val wrapper = DummyWrapper()
whenever(wrapper.foo).thenReturn(mockCompanionObj)
wrapper.callCompanionMethod()
verify(mockCompanionObj).someCompanionMethod()
....
}
Solution 2: using Mockk Mocking companion object in Mockk is easy. There is no need to insert a test interfacing object in the source code.
@Test
fun testCompanionObject() {
// Mock the companion object
mockkObject(DummyCompanion.Companion)
// Define the stubbing behavior of a companion object method
every { DummyCompanion.someCompanionMethod() } answers { stubMethod() }
val testObject = DummyWrapper()
// Call a method that calls the companion object method
// You can verify stubMethod() is called
testObject.callCompanionMethod()
verify(exactly = 1) { DummyCompanion.someCompanionMethod() }
}
For details see Mockk
Upvotes: 28
Reputation: 754
Here is one more solution that doesn't require Mockk or PowerMock.
helper
) in the calling class. Now it can be mocked normally in unit tests.interface IStaticHelper {
fun foo(): String
fun bar(): String
}
class StaticHelper {
companion object : IStaticHelper {
override fun foo() = "foo"
override fun bar() = "bar"
}
}
class Caller(private val helper: IStaticHelper = StaticHelper.Companion) {
fun callsTheHelper(): String {
return helper.foo()
}
}
class CallerTest {
@Test
fun testCallsTheHelper() {
val helper = mock()
val caller = Caller(helper)
assertThat(caller.callsTheHelper()).isEqualTo("foo")
}
}
While it's true that the caller in this case is no longer making static method calls, other classes can continue to do so unchanged.
Upvotes: 3
Reputation: 645
You can do so with PowerMock too, it'd be like this:
@RunWith(PowerMockRunner.class)
@PrepareForTest({DummyCompanion.class})
public class staticClassTest {
@Test
public void testForCompanionMethod() {
PowerMockito.mockStatic(DummyCompanion.class);
DummyCompanion.Companion companionMock = PowerMockito.mock(DummyCompanion.Companion.class);
Whitebox.setInternalState(
DummyCompanion.class, "Companion",
companionMock
);
DummyWrapper testObject = new DummyWrapper();
testObject.callCompanionMethod();
Mockito.verify(companionMock,Mockito.times(1)).someCompanionMethod();
}
}
Kotlin creates for Java (in the Kotlin class, which is DummyCompanion
in this case) a static field of its Companion subclass named Companion
which can be set using PowerMock's WhiteBox.setInternalState
tool to a mocked Companion
instance that you can later verify method calling to.
Upvotes: 8