模拟一个尤里卡假装客户进行单元测试 [英] Mock an Eureka Feign Client for Unittesting

查看:79
本文介绍了模拟一个尤里卡假装客户进行单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Spring Cloud的eureka和feign在某些服务之间进行通信(让我们说A和B).现在,我想对单个服务(A)的服务层进行单元测试.问题在于,该服务(A)正在使用伪装客户端请求其他服务(B)的某些信息.

在没有任何特殊配置的情况下运行单元测试会引发以下异常:java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-b =>但我不希望任何服务器运行.

我的问题是:有没有办法模拟假客户端,这样我就可以在不运行eureka实例和服务(B)的情况下对服务(A)进行单元测试?

我最终为假客户创建了一个存根.存根被标记为在测试中强制弹簧实例化存根的主要组件.
这是我想出的解决方案.

//the feign client
@FeignClient("user") 
public interface UserClient { 
    UserEntity getUser(); 
}

//the implementation i use for the tests 
@Component 
@Primary //mark as primary implementation
public class UserClientTestImpl implements UserClient { 
    @Override public UserEntity getUser() { 
        return someKindOfUser; 
    } 
}

解决方案

问题是...您甚至需要嘲笑吗?我经常看到人们提到模拟"是不应该作为单元测试的一部分"的第一个解决方案.模拟是一种技术,而不是万能的解决方案. (请参见此处).

如果您仍处于代码的早期阶段,则只需重构并使用其他内容即可,而不必依赖于Feign Client的具体实例.您可以使用接口,抽象类,特征或任何您想要的东西.不要依赖于对象本身,否则必须模拟"它.

public interface IWebClient {
  public String get(...);
  public String post(...);
} 

问题:但是我将有其他代码执行完全相同的操作(除了将在Feign的具体实例上执行),然后该怎么办? 好吧,您可以编写一个功能测试并调用一个可以在本地设置的Web服务器的实例-或使用Wiremock,如Marcin Grzejszczak在回答之一中提到的那样.

public class FeignClientWrapper implements IWebClient {
  private feign = something

  public String get() {
    feign.get( ... ) 
  }

  public String post() {
    feign.post( ... ) 
  }
} 

单元测试用于测试算法是否循环:单元如何工作.不要编写使模拟适合的代码-相反,它必须是相反的:您的代码应具有较少的依赖关系,并且仅在需要验证行为时才应该模拟(否则可以使用存根或伪造的对象):您需要验证行为吗?您是否需要测试代码中是否调用了特定方法?还是某个特定的方法连续被X,Y和Z调用了3次?好吧,那么是的,嘲笑是可以的.

否则,请使用伪造的对象:您想要的只是测试呼叫/响应以及状态码.您可能想要做的只是测试您的代码如何响应不同的输出(例如,JSON响应中是否存在错误"字段),不同的状态代码(假设客户端文档是正确的:GET,201、200 OK) POST等).

i am using spring cloud's eureka and feign to communicate between some services (lets say A and B). Now id like to unittest my service layer of a single service (A). The problem is, that this service (A) is using a feign client to request some information of the other service (B).

Running the unittests without any special configuration throws the following exception: java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-b => but i do not want any server to run.

My question is: Is there a way to mock the feign client, so i can unittest my service (A) without running an eureka instance and service (B)?

Edit: I ended up creating a stub for the feign client. The stub is marked as a primary component to force spring instantiating the stub within my tests.
This is the solution i came up with.

//the feign client
@FeignClient("user") 
public interface UserClient { 
    UserEntity getUser(); 
}

//the implementation i use for the tests 
@Component 
@Primary //mark as primary implementation
public class UserClientTestImpl implements UserClient { 
    @Override public UserEntity getUser() { 
        return someKindOfUser; 
    } 
}

解决方案

The question is ... do you even need to mock? I often see that people mention "mock" as the first solution to anything that "should not be part of the unit test". Mocking is a technique, not the solution to everything. (see here).

If you are still at the early stages of your code, just refactor and use something else instead of depending on the concrete instance of the Feign Client. You might use an interface, an abstract class, a trait or whatever you want. Don't depend on the object itself, otherwise you have to "mock it".

public interface IWebClient {
  public String get(...);
  public String post(...);
} 

To the question: but I will have other code that will do exactly the same (except that it will be on the concrete instance of Feign), what do I do then? Well, you can write a functional test and call an instance of a web server that you can setup locally - or use Wiremock, as mentioned by Marcin Grzejszczak in one of the answers.

public class FeignClientWrapper implements IWebClient {
  private feign = something

  public String get() {
    feign.get( ... ) 
  }

  public String post() {
    feign.post( ... ) 
  }
} 

Unit tests are used to test algorithms, if/else, loops: how units work. Don't write code to make mocks fit - it must be the other way around: your code should have less dependencies, and you should mock only when you need to verify the behavior (otherwise you can use a stub or a fake object): do you need to verify the behavior? Do you need to test that a particular method gets called in your code? Or that a particular method gets called with X, Y, and Z for 3 times in a row? Well, then yes, mocking is ok.

Otherwise, use a fake object: what you want is to test just the call/response and maybe the status code. All you probably want is to test how your code reacts to different outputs (e.g., the field "error" is present or not in a JSON response), different status codes (assuming that the Client documentation is right: 200 OK when GET, 201 when POST, etc).

这篇关于模拟一个尤里卡假装客户进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆