我们如何在单元测试时使用Mockito模拟来自另一个类的响应

时间:2017-06-05 22:05:07

标签: java mockito

我有一个方法来测试哪个是调用另一个类来获取一些信息:

public ClassToTest {

    public void methodToTest() {
        AnotherClass ac = Factory.getInstance();
        ResponseObj response = ac.anotherMethod();
    }
}

AnotherClass是另一个JAR的一部分,我想模仿它的响应(具体模拟ResponseObj响应)

如何使用Mockito实现这一目标?

2 个答案:

答案 0 :(得分:4)

首先,您需要让您的课程可测试。这意味着您需要从AnotherClass ac = Factory.getInstance()提取对象创建(methodToTest)到实例字段,或者可能需要单独的方法(以便能够模拟它),甚至更好 - 在类之外创建对象并传递它通过构造函数。因此,您的受测试类应如下所示:

public class ClassToTest {

    private AnotherClass ac;

    public ClassToTest(AnotherClass ac) {
        this.ac = ac;
    }

    public void methodToTest() {
        ResponseObj response = ac.anotherMethod();
        response.smth();
    }
}

然后,您需要将AnotherClass和ResponseObj声明为测试类中的字段,并将它们初始化为模拟。

AnotherClass ac = Mockito.mock(AnotherClass.class);
ResponseObj responseMock = Mockito.mock(ResponseObj.class);

之后你可以模拟方法调用:

when(anotherClassMock.anotherMethod()).thenReturn(responseMock);

最后,您的测试类应如下所示:

public class ClassToTestTest {

    private AnotherClass anotherClassMock = mock(AnotherClass.class);
    private ResponseObj responseMock = mock(ResponseObj.class);
    private ClassToTest classToTest = new ClassToTest(anotherClassMock);

    @Test
    public void test() {
        when(anotherClassMock.anotherMethod()).thenReturn(responseMock);

        classToTest.methodToTest();

        verify(responseMock, only()).smth();
    }
}

如果您无法更改ClassToTest的公共API,您可以使用Mockito间谍和受保护方法。

public class ClassToTest {

    public void methodToTest() {
        AnotherClass ac = constructAnotherClassObj();
        ResponseObj response = ac.anotherMethod();
        response.smth();
    }

    protected AnotherClass constructAnotherClassObj() {
        return Factory.getInstance();
    }
}


public class ClassToTestTest {

    private AnotherClass anotherClassMock = mock(AnotherClass.class);
    private ResponseObj responseMock = mock(ResponseObj.class);
    private ClassToTest classToTest = spy(new ClassToTest());

    @Test
    public void test() {
        when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
        when(classToTest.constructAnotherClassObj()).thenReturn(anotherClassMock);

        classToTest.methodToTest();

        verify(responseMock, only()).smth();
    }
}

答案 1 :(得分:0)

虽然@arsen_adzhiametov 的 the answer 是正确的,并且达到了标准,但我想贡献我的做法。

在这种情况下,我模拟了 HomeClient 的值,它在内部是一个 WebClient,它为某些值调用另一个服务。

TestClass.java(请更好地命名)

...
import org.mockito.Mockito;
...

class TestClass {
    HomeClient mockHomeClient;

    @BeforeEach
    void setup() {
        mockHomeClient = Mockito.mock(HomeClient.class);
        
        // Axon specific test code. Can ignore if not using Axon.
        fixture = new AggregateTestFixture<>(SomeAgreegate.class);
        fixture.registerInjectableResource(mockHomeClient);
    }
    
    @Test
    void testOpenOperation() throws HomeClientException {
        Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(2);
        // Do what you will with your code and call the method which you want to test
        // Mockito will mock the `HomeClient` in this case and `getXYZ` will return `2`
        // You can also change the mock response any time in the same function
        Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(-100);

        // Or specify different results on mock when different values are provided
        Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(1);
        Mockito.when(mockHomeClient.getXYZ("foo")).thenReturn(100);        
        Mockito.when(mockHomeClient.getXYZ("bar")).thenReturn(0);


    }
}