2018.01.15更新
后來在我司架構(gòu)師的指點(diǎn)下,我改用了一種更優(yōu)雅友好的方式來對FeignClient對象進(jìn)行Mock既荚。
首先我們需要一個(gè)jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
spring的這個(gè)jar包下自帶Mock相關(guān)內(nèi)容贴唇。只需要在Test類中使用@MockBean
聲明我們所要Mock的FeignClient對象即可搀绣。
如:
@MockBean
private IPromotionController feignPromotionMock
PS:當(dāng)你需要進(jìn)一步使用這個(gè)對象時(shí),你需要自己寫相應(yīng)的斷言戳气。
以上链患。
--------------------------------------2018.01.15更新分割線------------------------------------------------
前言
在搜索引擎使用關(guān)鍵詞mock+feignclient搜索,搜索結(jié)果中最相關(guān)的就是StackOverFlow上的《How to mock feign.Client.Default with Mockito》了瓶您。
本文將會(huì)基于此問答中麻捻,用戶yuz的回答展開纲仍。
該回答提供了一種手動(dòng)模擬對象的實(shí)現(xiàn)方式。至于這種方式屬于mock還是stub贸毕,就見仁見智了郑叠。
本文由作者三汪首發(fā)于簡書。
擴(kuò)展閱讀:
- 《Mocks Aren't Stubs》
- 《Stubs和Mocks區(qū)別 (Stubs vs. Mocks)》(這篇是提取中心思想翻譯過來的《Mocks Aren't Stubs》)
- 《初識stub和mock--junit的兩種測試策略》
- 《Mock an Eureka Feign Client for Unittesting》
正文
yuz的回答內(nèi)容如下:
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...
}
補(bǔ)充和說明
上面的答案可以很好地實(shí)現(xiàn)對FeignClient的mock明棍,但我們需要作進(jìn)一步的補(bǔ)充乡革,如下。具體的修改原因隨后附上击蹲。
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支持這個(gè)規(guī)范,也可以使用@Inject來實(shí)現(xiàn)注入。但是通常在Spring中習(xí)慣使用@Autowired來實(shí)現(xiàn)注入歌豺,能用一個(gè)東西解決就用一個(gè)東西解決,我們沒有必要讓代碼更復(fù)雜心包。因此建議使用@Autowired來替代原文中的@Inject类咧。
擴(kuò)展閱讀:《@Inject和@Autowired以及@Resource區(qū)別》MyService.java
中原文可能漏掉了@Service注解,在此做了補(bǔ)充蟹腾。【重要】:通過構(gòu)造函數(shù)new出來的service對象痕惋,沒有在構(gòu)造函數(shù)中初始化的其他注入會(huì)為空。
在此我特地在MyService.java
中注入了MyRepository
并修改了相應(yīng)構(gòu)造函數(shù)進(jìn)行示例娃殖。
如果構(gòu)造函數(shù)中像原文一樣只傳入MyFeignClient
的實(shí)現(xiàn)值戳,那么由于MyRepository
沒有被初始化,在調(diào)用myMethod()
時(shí)會(huì)出現(xiàn)NullPointerException炉爆。
同時(shí)堕虹,這也提現(xiàn)了這種實(shí)現(xiàn)方式的一個(gè)弊端:對注入對象多的Service不友好。望周知芬首。
以上赴捞。
希望我的文章對你能有所幫助。
我不能保證文中所有說法的百分百正確郁稍,但我能保證它們都是我的理解和感悟以及拒絕復(fù)制黏貼赦政。
有什么意見、見解或疑惑耀怜,歡迎留言討論恢着。