java unittest mock_如何使用Mock/Stub模拟对象来对FeignClient进行单元测试(UnitTest)

本文介绍了如何在Java单元测试中使用@MockBean模拟FeignClient对象,以进行更优雅的测试。通过在Test类中声明@MockBean,并在setUp方法中注入Mock对象,可以避免手动创建复杂的模拟实现。同时,文章提醒了在使用MockBean时要注意对象的依赖注入,以防止NullPointerException的发生。
摘要由CSDN通过智能技术生成

2018.01.15更新

后来在我司架构师的指点下,我改用了一种更优雅友好的方式来对FeignClient对象进行Mock。

首先我们需要一个jar包

org.springframework.boot

spring-boot-starter-test

test

spring的这个jar包下自带Mock相关内容。只需要在Test类中使用@MockBean声明我们所要Mock的FeignClient对象即可。

如:

@MockBean

private IPromotionController feignPromotionMock

PS:当你需要进一步使用这个对象时,你需要自己写相应的断言。

以上。

--------------------------------------2018.01.15更新分割线------------------------------------------------

前言

在搜索引擎使用关键词mock+feignclient搜索,搜索结果中最相关的就是StackOverFlow上的《How to mock feign.Client.Default with Mockito》了。

本文将会基于此问答中,用户yuz的回答展开。

该回答提供了一种手动模拟对象的实现方式。至于这种方式属于mock还是stub,就见仁见智了。

本文由作者三汪首发于简书。

扩展阅读:

正文

yuz的回答内容如下:

As mentioned before, Mockito is not powerful enough. I solved this with a manual mock.

It's easier than it sounds:

MyService.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();

}

If you want to test the code above while mocking the feignclient, do this:

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...

}

补充和说明

上面的答案可以很好地实现对FeignClient的mock,但我们需要作进一步的补充,如下。具体的修改原因随后附上。

MyService.Java

@Service

public class MyService{

//My service stuff

@Autowired

private MyFeignClient myFeignClient;

@Autowired

private MyRepository myRepository;

@Autowired

public MyService(MyFeignClient myFeignClient,MyRepository myRepository){

this.myFeignClient = myFeignClient;

this.myRepository = myRepository;

}

public void myMethod(){

myFeignClient.remoteMethod(); // We want to mock this method

myRepository.findAll();

}

}

MyFeignClient.Java

@FeignClient("target-service")

public interface MyFeignClient{

@RequestMapping(value = "/test" method = RequestMethod.GET)

public void remotemethod();

}

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;

@Autowired

private MyFeignClientMock myFeignClientMock;

@Autowired

private MyRepository myRepository;

@Before

public void setUp(){

this.myService = new MyService(myFeignClientMock,myRepository); //inject the mock

}

@Test

public void Test(){

myService.myMethod();

}

//Do other tests normally here...

}

说明:

@Inject是jsr330中的东西。由于Spring支持这个规范,也可以使用@Inject来实现注入。但是通常在Spring中习惯使用@Autowired来实现注入,能用一个东西解决就用一个东西解决,我们没有必要让代码更复杂。因此建议使用@Autowired来替代原文中的@Inject。

扩展阅读:《@Inject和@Autowired以及@Resource区别》

MyService.java中原文可能漏掉了@Service注解,在此做了补充。

【重要】:通过构造函数new出来的service对象,没有在构造函数中初始化的其他注入会为空。

在此我特地在MyService.java中注入了MyRepository并修改了相应构造函数进行示例。

如果构造函数中像原文一样只传入MyFeignClient的实现,那么由于MyRepository没有被初始化,在调用myMethod()时会出现NullPointerException。

同时,这也提现了这种实现方式的一个弊端:对注入对象多的Service不友好。望周知。

以上。

希望我的文章对你能有所帮助。

我不能保证文中所有说法的百分百正确,但我能保证它们都是我的理解和感悟以及拒绝复制黏贴。

有什么意见、见解或疑惑,欢迎留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值