3

我正在编写一个Dropwizard应用程序并Feign用于构建对外部服务的客户端调用。我有我正在注册的自定义编码器和解码器,feign.Builder如下所示:

    this.feignBuilder = Feign.builder()
            .contract(new JAXRSContract()) // we want JAX-RS annotations
            .encoder(new JacksonEncoder()) // same as what dropwizard is using
            .decoder(new CustomDecoder())
            .errorDecoder(new CustomErrorDecoder())
            .requestInterceptor(new AuthKeyInterceptor(config.getInterceptor()));

我正在为feign客户端调用编写单元测试,因此我可以观察 feign 机器如何处理我的编码器/解码器覆盖和异常冒泡。我现在对使用假服务器编写集成测试不感兴趣(这是我看到人们为这种情况编写的最常见的测试类型)。

这应该是直截了当的。我想模拟feign发出请求的点并让它返回我的假响应。这意味着我应该模拟调用,feign.Client.Default.execute以便它在发出请求时返回我的虚假响应this call site。该模拟的示例如下:

String responseMessage = "{\"error\":\"bad\",\"desc\":\"blah\"}";
feign.Response feignResponse = FeignFakeResponseHelper.createFakeResponse(404,"Bad Request",responseMessage);
Client.Default mockFeignClient = mock(Client.Default.class);
try {
     when(mockFeignClient.execute(any(feign.Request.class),any(Request.Options.class))).thenReturn(feignResponse);
} catch (IOException e) {
     assertThat(true).isFalse(); // fail nicely
}

没运气。当我到达代码中请求的调用站点Cleint.Default时,该类不会被嘲笑。我究竟做错了什么?

4

2 回答 2

3

如前所述,Mockito 还不够强大。我用手动模拟解决了这个问题。

这比听起来容易:

我的服务.Java

public class MyService{
    //My service stuff      

    private MyFeignClient myFeignClient;

    @Inject //this will work only with constructor injection
    public MyService(MyFeignClient myFeignClient){
        this.MyFeignClient = myFeignClient
    }


    public void myMethod(){
        myFeignClient.remoteMethod(); // We want to mock this method
    }
}

MyFeignClient.Java

@FeignClient("target-service")
public interface MyFeignClient{

    @RequestMapping(value = "/test" method = RequestMethod.GET)
    public void remotemethod();
}

如果您想在模拟 feignclient 时测试上面的代码,请执行以下操作:

MyFeignClientMock.java

@Component
public class MyFeignClientMock implements MyFeignClient {

    public void remoteMethod(){
         System.out.println("Mocked remoteMethod() succesfuly");
    }
}

MyServiceTest.java

@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {

    private MyService myService;

    @Inject
    private MyFeignClientMock myFeignClientMock;

    @Before
    public void setUp(){
       this.myService = new MyService(myFeignClientMock); //inject the mock
    }

    //Do tests normally here...
}
于 2016-03-27T06:54:27.353 回答
2

事实证明,它Mockito的功能不足以做我认为它可以做的事情。正确的解决方案是使用PowerMockito模拟构造函数,以便Client.Default在包含该引用的类中实例化它时返回模拟实例。

在经历了很多编译错误的痛苦之后,我开始PowerMockito编译,它似乎可以工作了。唉,它没有返回我的模拟,电话仍在进行中。我过去曾尝试过PowerMockito,但由于它引起的额外问题而从未使用过它。所以我仍然认为即插即用并不容易。

很遗憾,尝试做这样的事情是如此困难。

于 2015-10-09T16:40:13.790 回答