称为验证伴随对象方法的单元测试(模拟伴随对象)

时间:2018-11-06 15:20:28

标签: java unit-testing kotlin

切换到Kotlin时,静态方法将移入一个伴随对象。但是,没有明显的方法可以对称为“静态方法”的其他方法进行单元测试。

在Java中,我们可以使用PowerMockito的MockStatic(SomeClass.class)来验证在测试方法中调用了静态方法。 PowerMock在Kotlin失去了魔力。

为了进行测试,我创建了以下类。

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")
        }
    }
}

现在有另一个类叫DummyCompanion.someCompanion

public class DummyWrapper {
    public void callAStaticMethod(){
        Dummy.staticMechod();
    }

    public void callCompanionMethod(){
        DummyCompanion.Companion.someCompanionMethod();
    }
}

要进行单元测试callAStaticMethod(),我们使用了以下

@RunWith(PowerMockRunner.class)
@PrepareForTest({Dummy.class, DummyCompanion.Companion.class})
public class staticClassTest {
    //This case works
    @Test 
    public void testForStaticMethod() {
        PowerMockito.mockStatic(Dummy.class);   
        DummyWrapper testObject = new DummyWrapper();

        Mockito.when(Dummy.staticMechod()).thenCallRealMethod();

        testObject.callAStaticMethod();

        PowerMockito.verifyStatic(Dummy.class);
        Dummy.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();
}

我的问题是如何验证伴随方法的调用。

3 个答案:

答案 0 :(得分:2)

解决方案1:在调用类中添加一个调用者函数

public class DummyWrapper {
val foo get() = DummyCompanion.Companion

public void callAStaticMethod(){
    foo.staticMechod();
}

public void callCompanionMethod(){
    foo.someCompanionMethod();
}
}

在测试类中,我们可以使用Mockito为get()函数提供一个存根,并验证它是否被调用。

@Test
fun testCase{
....
val mockCompanionObj: DummyCompanion.Companion = mock()
val wrapper = DummyWrapper()

whenever(wrapper.foo).thenReturn(mockCompanionObj)
wrapper.callCompanionMethod()
verify(mockCompanionObj).someCompanionMethod()
....
}

解决方案2:使用Mockk 在Mockk中模拟伴侣对象很容易。无需在源代码中插入测试接口对象。

 @Test
 fun testCompanionObject() {
    //Mock the companion object
    mockkObject(DummyCompanion.Companion)

    //define the stubbing bechavior of a companion object method
    every { DummyCompanion.Companion.companionMethod() } 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() }
}

有关详细信息,请参见Mockk

答案 1 :(得分:1)

这是又一个不需要Mockk或PowerMock的解决方案。

  1. 从伴随对象中提取接口,并将其放置在同一个文件中,但不在类之外。
  2. 让伴随对象从接口继承
  3. 向调用静态方法的类的构造函数添加一个新的可选属性。它的默认值应该是伴随对象。
  4. 在调用类中切换为使用实例调用(小写helper)。现在可以在单元测试中正常模拟它了。
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")
    }
}

在这种情况下,确实是调用者不再进行静态方法调用,而其他类可以继续不变。

答案 2 :(得分:0)

您也可以使用PowerMock这样做,就像这样:

@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为Java(在这种情况下为Kotlin类,在DummyCompanion中)创建了名为Companion的Companion子类的静态字段,可以使用PowerMock的WhiteBox.setInternalState工具将其设置为一个模拟的Companion实例,您以后可以验证对其进行调用的方法。