Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 250 Vote(s) - 3.38 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Unit Testing verifying a companion object method is called (mocking a companion object)

#1
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.
Reply

#2
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.
Reply

#3
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.
Reply

#4
**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]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through