Mockito验证方法在void方法内的调用

时间:2019-10-17 09:06:53

标签: java mocking mockito

我有以下要测试的类和方法:

public class MyClass{
    private MyObject svc;
    private MyObject2 svc2;

    public MyClass(MyObject svc){
        this.svc = svc;
        this.svc2 = new MyObject2(svc);
    }


    public void getSvc(){
        Result response = this.svc.getResponse();
        if(!response.isEmpty())
             this.svc2.filterResponse(response);
        else
            System.out.println("empty");
    }

}

但是我正在努力成为无效方法。我该如何测试filterResponse仅在我的响应不为空时被调用?

3 个答案:

答案 0 :(得分:2)

这是一个设计问题,因为被测对象对其执行设计功能的真正需求并不诚实。它通过new MyObject2(...)紧密地耦合自身,从而使隔离测试变得困难(并非不可能)。

MyObject2依赖于MyObject的事实是MyClass不需要了解的实现细节。

遵循显式依赖原理,

  

方法和类应明确要求(通常通过方法参数或构造函数参数)它们所需的任何协作对象,以使其正常运行。

MyClass应该相应地重构

public class MyClass{
    private MyObject svc;
    private MyObject2 svc2;

    public MyClass(MyObject svc, MyObject2 svc2){
        this.svc = svc;
        this.svc2 = svc2;
        //this.svc2 = new MyObject2(svc); // <-- remove implementation details
    }

    public void getSvc(){
        Result response = this.svc.getResponse();
        if(!response.isEmpty())
             this.svc2.filterResponse(response);
        else
            System.out.println("empty");
    }
}

允许在进行单独测试时将必要的模拟/存根明确地注入到测试对象中。

//Arrange
MyObject svc = mock(MyObject.class);
MyObject2 svc2 = mock(MyObject2.class);

MyClass subject = new MyClass(svc, svc2);

Result response = mock(Result.class);
when(response.isEmpty()).thenReturn(false);

when(svc.getResponse()).thenReturn(response);

//Act
subject.getSvc();

//Assert
verify(svc2, times(1)).filterResponse(response); //verify method call inside void method

被测方法为void的事实与验证行为无关。

答案 1 :(得分:0)

如果打算使用这种设计,并且您不能修改现有代码。您可以采用以下方法:

  1. 在您的Test课程内。声明新的静态内部类(例如:InternalMyClass),以扩展您的MyClass
  2. 使用2个参数将新的构造函数添加到内部类中。
  3. 现在在测试用例中,使用内部类构造MyClass。您现在可以通过MyObject2的间谍/存根了。

答案 2 :(得分:0)

您应该对myClass进行自动装配或注入模拟,因为它应该创建一个bean,以便在调用getSvc()时应该满足您的条件