如何使用顺序调用测试 void 函数

How to test a void function with sequential calls

如何测试一个函数,它没有 return 一个值,而是使用给定的参数来构造一些被发送到顺序函数的值?

例如

public void handleSomeEvent(String str1, String str2){
   MyObject obj1 = new MyObject();
   obj1.setParameterA(str1);
   obj2.setParameterB(str2);
   EventHandler.getInstance().notify(obj1)
}

在上面的示例中,我想验证 EventHandler.notify 是使用包含 str1 作为 parameterAstr2 作为 parameter2 的对象调用的。这可以使用一些常见的模拟框架(即 mockito)来完成吗?

您可以执行以下操作

@RunWith(PowerMockRunner.class)
@PrepareForTest({ EventHandler.class })
public class UnderTestTest {

@Test
public void testLoadUniqueOrNull() throws NKFException {
    PowerMockito.mockStatic(EventHandler.class);

    EventHandler handler = PowerMockito.mock(EventHandler.class);
    PowerMockito.when(EventHandler.getInstance())
            .thenReturn(handler);

    ArgumentCaptor<MyObject> handlerArg = 
    ArgumentCaptor.forClass(MyObject.class);
    PowerMockito.doNothing()
            .when(handler)
            .notify(handlerArg.capture());

    new UnderTest().handleSomeEvent("test");
    Assert.assertEquals(new MyObject("test"), handlerArg.getAllValues()
            .get(0));
}

}


public class UnderTest {
    public void handleSomeEvent(String str1) {
        MyObject obj1 = new MyObject(str1);

        EventHandler.getInstance()
                .notify(obj1);
    }
}


public class MyObject {

    private final String x;

    public MyObject(String x) {
        this.x = x;
    }

    @Override
    public boolean equals(Object obj) {
        return ((MyObject) obj).x == x;
    }
}


public class EventHandler {

    private final static EventHandler e = new EventHandler();

    public static EventHandler getInstance() {
        return e;
    }

    public void notify(MyObject obj) {
        // whatever
    }
}

(附注这个快速代码是为了演示功能而不是编码的最佳实践)

在需要验证被调用参数的情况下,使用 MockitoArgumentCaptor<T>

查看参考资料: https://static.javadoc.io/org.mockito/mockito-core/2.6.9/org/mockito/ArgumentCaptor.html

Unittest 验证 public 可观察到的行为 其中 "public" 表示 通过单元 API 并且"behavior" 表示 return 值 and/or 与依赖项的通信.

您的代码具有 隐藏依赖性,由对 EventHandler 对象的 静态访问 引入。我假设您的 EventHandler class 包含 Java 单身模式 。这是我们大多数人 STUPID code 的开始。

你不应该屈服于使用 PowerMock 的糟糕设计。

更好的方法是将 EventHandler 对象作为 构造函数参数 传递给您的测试代码,如下所示:

    class MyTestedClass{
       private final EventHandler eventHandler;
       class MyTestedClass(EventHandler eventHandler){
          this.eventHandler=eventHandler;
       }

       public void handleSomeEvent(String str1, String str2){
          MyObject obj1 = new MyObject();
           obj1.setParameterA(str1);
           obj2.setParameterB(str2);
           eventHandler.notify(obj1)
        }
    }

然后让您的 EventHandler 成为您可以继承的普通 class。 (至少从 class 声明中删除 final 关键字)。

然后您可以使用普通 Mockito 将 EventHandler 对象替换为测试替身并验证您的代码与该测试替身的通信:

    class MyTestedClassTest{
       @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); 
       @Mock private EventHandler eventHandler; // ignores the private constructor
       class MyTestedClass(EventHandler eventHandler){
          this.eventHandler=eventHandler;
       }

       @Test
       public void notifiesEventHandlerWithDTO(String str1, String str2){

           new UnderTest(eventHandler).handleSomeEvent("test1","test2");

           ArgumentCaptor<MyObject> handlerArg = ArgumentCaptor.forClass(MyObject.class);
           verify(eventHandler).notify(handlerArg.capture());
           assertThat("parameter A passed to object",
                       handlerArg.getValue().getParameterA(),
                       equalTo("test1"));
           assertThat("parameter B passed to object",
                       handlerArg.getValue().getParameterB(),
                       equalTo("test2"));
        }
    }