用Mockito模拟外部服务

时间:2018-07-27 08:53:19

标签: unit-testing mockito

我有一个具有以下结构的应用程序:

  

客户端类:

class Client{
    private Requests requests;
    private Settings settings;
    protected Client(Settings settings){
        this.settings = settings;
        this.requests = new Requests(settings);
    }
    public Requests getRequests(){
        return requests;
    }
}
  

请求类:

class Requests{
    private RequestsHandler requestsHandler;
    private Settings settings;

    protected Requests(Settings settings){
        this.requestHandler = new RequestHandler();
        this.settings = settings;
    }

    public Bicycles getBicycles(BicyclesParameters bicycleParams){
        return requestsHandler.callService(bicycleParams, settings, "service/getBicycles", Bicycles.class)
    }
}

还有我的

  

RequestsHandler类:

class RequestsHandler{
        public BaseResponse callService(BaseParams params, Settings settings, String serviceURL, Class<? extends BaseResponse> responseType ) {

            here I use RestTemplate to get data from external Service

        }
    }

在单元测试中,我想模拟来自外部服务的数据,所以我做了如下操作: 创建一个模拟 RequestsHandler 对象,模拟 callService 方法,并使用 @Bean 注册该模拟对象:

@Configuration
public class TestConfiguration {
    @Bean
    public RequestsHandler requestsHandler() {
        RequestsHandler requestsHandler = Mockito.mock(RequestsHandler.class);
        when(requestsHandler.callService(new BicyclesParameters(), new Settings(),
                "/service/getBicyles", Bicycles.class))
                        .thenReturn(new Bicycles().setBicyclesList(new Bicycle[] {new Bicycle(), new Bicycle()}));
        return requestsHandler;
    }
}

和我的测试班:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class TestGetBicycles{

    @Test
    public void testGetBicycles() {
        Client = new Client(new Settings);
        Bicycles bicycles = client.getRequests.getBicycles(new BicyclesParamters());
        assertNotNull(bicycles.getBicyclesList());
    }

}

但是当我运行测试时,我遇到两个问题:

  1. 我成为
  

org.mockito.exceptions.misusing.InvalidUseOfMatchersException

,我不知道为什么,但是当我将模拟对象更改为:

 when(requestsHandler.callService(any(), any(),
                any(), any()))
                        .thenReturn(new Bicycles().setBicyclesList(new Bicycle[] {new Bicycle(), new Bicycle()}));

错误消失了,但是

  1. 我成为的结果不是模拟结果,而是来自外部服务的结果。这意味着没有考虑模拟对象。

有人可以在这些时候帮助我吗?这是我第一次与Mockito合作,所以现在我很困惑。

谢谢你!

1 个答案:

答案 0 :(得分:3)

您创建了一个模拟,但从未在执行的方法范围内使用。

实际上,您的问题是您想模拟在调用测试方法期间创建的对象内部创建的对象:

protected Requests(Settings settings){
    this.requestHandler = new RequestHandler(); // <- You want to mock this field
    this.settings = settings;
}

使用普通嘲笑是不可能的。就您而言,您有两种方法:

1)重构您的代码,以提供一个接受RequestHandler作为参数的其他构造函数。在您的情况下,ClientRequests可以接受RequestHandler
例如Client

protected Client(Settings settings, RequestsHandler requestHandler){
    this.settings = settings;
    this.requests = new Requests(settings, requestHandler);
}

您进行的测试可能类似于:

@Mock
RequestsHandler requestsHandlerMock;
...
@Test
public void testGetBicycles() {
    Client = new Client(new Settings(), requestsHandlerMock);
    Bicycles bicycles = client.getRequests.getBicycles(new BicyclesParamters());
    //...
}

2)使用运行时依赖于反射和字节代码生成(如CGLib)的库。为此,PowerMock和PowerMockito在Java中是众所周知的。

我个人认为重构是可能的。它使代码始终更加清晰和整洁。实际上,这些库本身并不坏,但可能会造成一些技术负担,因为经常使用它们可能会鼓励您在库的帮助下进行 cheat 而不是改进代码的API,测试。