
該圖片由NickyPe在Pixabay上發布
你好,我是看山,
今天聊聊如何在 SpringBoot 中集成 Junit5、MockMvc、Mocktio,Junit5 是在 Java 堆疊中應用最廣的測驗框架,Junit4 一度霸榜,
升級到 Junit5 之后,除了增加 Java8 的很多特性,做了很多功能增強,在結構上做了優化調整,拆分了很多不同的模塊,可以按需引入,比如:
- JUnit Platform - 在 JVM 上啟動測驗框架
- JUnit Jupiter - 在 JUnit5 中撰寫測驗和擴展
- JUnit Vintage - 提供運行基于 JUnit3 和 JUnit4 的測驗引擎
從 SpringBoot 2.2.0 之后,Junit5 已經成為了默認的 Junit 版本,有了 JUnit Vintage,從 Junit4 遷移到 Junit5 的成本極低,所以本文就直接針對 Junit5 開始了,
版本
先說版本,是為了避免因為版本差異出現各種奇怪的問題:
- JDK:jdk8(小版本可以忽略)
- SpringBoot:2.5.2
- 繼承
spring-boot-starter-parent - 依賴
spring-boot-starter-web - 依賴
spring-boot-starter-test
- 繼承
- JUnit:5.7.2
- Mockito:3.9.0
- hamcrest:2.2
SpringBoot 的好處在于,只要繼承spring-boot-starter-parent或引入spring-boot-pom-dependencies,然后添加spring-boot-starter-test依賴即可,定義的 POM 內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
</parent>
<groupId>cn.howardliu.effective.spring</groupId>
<artifactId>springboot-junit5-mockito</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-junit5-mockio</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
因為繼承了spring-boot-starter-parent,所以我們依賴的spring-boot-starter-test不需要寫具體的版本,可以直接集成父級的版本定義,其中,spring-boot-starter-web是用于提供 REST API 的 web 容器,spring-boot-starter-test可以提供各種測驗框架的,spring-boot-maven-plugin是將 SpringBoot 應用打包為可執行 jar 的插件,
專案結構
因為是 DEMO 示例,我們實作一個 Echo 介面,能夠接收請求引數,并回傳加工后的字串,按照慣例,我們使用萬能的Hello, World!,
我們的專案結構如下:
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── cn
│ │ └── howardliu
│ │ └── effective
│ │ └── spring
│ │ └── springbootjunit5mockio
│ │ ├── SpringbootJunit5MockioApplication.java
│ │ ├── controller
│ │ │ └── EchoController.java
│ │ └── service
│ │ ├── EchoService.java
│ │ └── impl
│ │ └── EchoServiceImpl.java
│ └── resources
│ └── application.yaml
└── test
└── java
└── cn
└── howardliu
└── effective
└── spring
└── springbootjunit5mockio
└── controller
├── EchoControllerMockTest.java
└── EchoControllerNoMockitoTest.java
- SpringbootJunit5MockioApplication:SpringBoot 應用啟動入口
- EchoController:介面定義
- EchoService:實作業務邏輯介面
- EchoServiceImpl:介面實作
- EchoControllerMockTest:使用 Mock 代理 EchoService 實作
- EchoControllerNoMockitoTest:直接測驗介面實作
EchoServiceImpl
我們看下EchoService的實作,這將是我們 DEMO 的核心實作:
@Service
public class EchoServiceImpl implements EchoService {
@Override
public String echo(String foo) {
return "Hello, " + foo;
}
}
EchoControllerNoMockitoTest
我們先使用 Junit5+MockMvc 實作 Controller 介面的普通呼叫,代碼如下:
@SpringBootTest(classes = SpringbootJunit5MockioApplication.class)
@AutoConfigureMockMvc
class EchoControllerNoMockitoTest {
@Autowired
private MockMvc mockMvc;
@Test
void echo() throws Exception {
final String result = mockMvc.perform(
MockMvcRequestBuilders.get("/echo/")
.param("name", "看山")
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn()
.getResponse()
.getContentAsString(StandardCharsets.UTF_8);
Assertions.assertEquals("Hello, 看山", result);
}
}
我們通過SpringBootTest注解定義這是一個 SpringBoot 應用的測驗用例,然后通過AutoConfigureMockMvc啟動測驗容器,這樣,就可以直接注入MockMvc實體測驗 Controller 介面,
這里需要注意一點,網上很多教程會讓寫@ExtendWith({SpringExtension.class})這樣一個注解,其實完全沒有必要,通過原始碼我們可以知道,SpringBootTest注解已經添加了ExtendWith,
EchoControllerMockTest
這個測驗用例中,我們通過 Mockito 組件代理EchoService的echo方法,代碼如下:
@SpringBootTest(classes = SpringbootJunit5MockioApplication.class)
@ExtendWith(MockitoExtension.class)
@AutoConfigureMockMvc
class EchoControllerMockTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private EchoService echoService;
@BeforeEach
void setUp() {
Mockito.when(echoService.echo(Mockito.any()))
.thenReturn("看山說:" + System.currentTimeMillis());
}
@Test
void echo() throws Exception {
final String result = mockMvc.perform(
MockMvcRequestBuilders.get("/echo/")
.param("name", "看山的小屋")
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn()
.getResponse()
.getContentAsString(StandardCharsets.UTF_8);
Assertions.assertTrue(result.startsWith("看山"));
}
}
在這個示例中,我們需要注意@ExtendWith(MockitoExtension.class)注解,這個注解是用于引入MockBean的,我們通過對echo方法的攔截,使其回傳我們定義好的回應結果,這種方式是為了在多系統或者多功能測驗時,不需要真正呼叫介面,
比如,我們需要獲取用戶手機號,通常在介面中會校驗用戶有沒有登錄,我們就可以使用 Mockito 的能力代理登錄驗證,使結果永遠是 true,
文末總結
至此,我們完成了 SpringBoot 集成 Junit5、MockMvc、Mockito 的示例,想要獲取原始碼,只需要關注公眾號「看山的小屋」,回復spring即可,
很多同學感覺單元測驗沒有撰寫的必要,直接使用 Swagger 或者 Postman 之類的工具就能很好的測驗介面,確實如此,對于簡單的 CRUD 介面,寫單元測驗的必要性不太高,但是,如果是復雜介面呢?介面引數有很多的組合,回應結果也需要各種驗證,如果使用一次性的工具,每次測驗組合引數就已經讓人崩潰了,而且組合引數不能存留甚至不能在多人間傳承,就會浪費很多的人力,
此時,單元測驗的效果就會顯現,我們只需要撰寫一次引陣列合,放在 csv 之類的檔案中,通過單元測驗的引數化測驗方式,即可多次運行,驗證介面的正確性,
或者,當我們感覺系統已經臭味彌漫,對其重構之后,為了驗證介面功能不變,也可以直接使用原來的測驗用例加以驗證,
綜上,雖然測驗用例撰寫麻煩,但是妙用無窮,
推薦閱讀
- SpringBoot 實戰:一招實作結果的優雅回應
- SpringBoot 實戰:如何優雅的處理例外
- SpringBoot 實戰:通過 BeanPostProcessor 動態注入 ID 生成器
- SpringBoot 實戰:自定義 Filter 優雅獲取請求引數和回應結果
- SpringBoot 實戰:優雅的使用列舉引數
- SpringBoot 實戰:優雅的使用列舉引數(原理篇)
- SpringBoot 實戰:在 RequestBody 中優雅的使用列舉引數
- SpringBoot 實戰:在 RequestBody 中優雅的使用列舉引數(原理篇)
- SpringBoot 實戰:JUnit5+MockMvc+Mockito 做好單元測驗
你好,我是看山,公眾號:看山的小屋,10 年老猿,開源貢獻者,游于碼界,戲享人生,
個人主頁:https://www.howardliu.cn
個人博文:SpringBoot 實戰:JUnit5+MockMvc+Mockito 做好單元測驗
CSDN 主頁:https://kanshan.blog.csdn.net/
CSDN 博文:SpringBoot 實戰:JUnit5+MockMvc+Mockito 做好單元測驗

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/299667.html
標籤:java
