0Day Forums
Unit Testing verifying a companion object method is called (mocking a companion object) - Printable Version

+- 0Day Forums (https://zeroday.vip)
+-- Forum: Coding (https://zeroday.vip/Forum-Coding)
+--- Forum: Kotlin (https://zeroday.vip/Forum-Kotlin)
+--- Thread: Unit Testing verifying a companion object method is called (mocking a companion object) (/Thread-Unit-Testing-verifying-a-companion-object-method-is-called-mocking-a-companion-object)



Unit Testing verifying a companion object method is called (mocking a companion object) - smoulders637149 - 07-20-2023

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.


RE: Unit Testing verifying a companion object method is called (mocking a companion object) - nebn758895 - 07-20-2023

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.


RE: Unit Testing verifying a companion object method is called (mocking a companion object) - krissyvajolb - 07-20-2023

Here is one more solution that doesn't require Mockk or PowerMock.

1. Extract an interface from the companion object and place it in the same file but outside of the class.
2. Have the companion object inherit from the interface
3. Add a new optional property to the constructor of the class calling the static methods. Its default value should be the companion object.
4. Switch to using instance calls (lowercase `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.


RE: Unit Testing verifying a companion object method is called (mocking a companion object) - immerge496736 - 07-20-2023

**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][1]





[1]:

[To see links please register here]