https://github.com/zq2599/blog_demosjava
內容:全部原創文章分類彙總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;git
《JUnit5學習》系列旨在經過實戰提高SpringBoot環境下的單元測試技能,一共八篇文章,連接以下:程序員
本文是《JUnit5學習》系列的第一篇,經過實戰學習在SpringBoot框架下JUnit5的基本功能,全篇章節以下:github
2. 從上圖可見,整個JUnit5能夠劃分紅三層:頂層框架(Framework)、中間的引擎(Engine),底層的平臺(Platform);
3. 官方定義JUnit5由三部分組成:Platform、Jupiter、Vintage,功能以下;
4. Platform:位於架構的最底層,是JVM上執行單元測試的基礎平臺,還對接了各類IDE(例如IDEA、eclipse),而且還與引擎層對接,定義了引擎層對接的API;
5. Jupiter:位於引擎層,支持5版本的編程模型、擴展模型;
6. Vintage:位於引擎層,用於執行低版本的測試用例;web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
@RunWith(SpringRunner.class) @SpringBootTest public class XXXTest {
3. 我們再來看看SpringBootTest註解,以下圖,可見已經包含了ExtendWith:spring
4. 綜上所述,SpringBoot+JUnit5時,RunWith註解已經不須要了,正常狀況下僅SpringBootTest註解便可,若是對擴展性有更多需求,能夠添加ExtendWith註解,以下圖:數據庫
注意,接下來提到的測試方法,是指當前class中全部被@Test、@RepeatedTest、@ParameterizedTest、@TestFactory修飾的方法;apache
如下的註解都是在5以前的版本使用的,如今已經被廢棄:編程
被廢棄的註解 | 新的繼任者 |
---|---|
Before | BeforeEach |
After | AfterEach |
BeforeClass | BeforeAll |
AfterClass | AfterAll |
Category | Tag |
RunWith | ExtendWith |
Rule | ExtendWith |
ClassRule | RegisterExtension |
整個系列的編碼和執行在如下環境進行,供您參考:api
爲了簡化代碼,項目中使用了lombok,請您在IDEA中安裝lombok插件;
名稱 | 連接 | 備註 |
---|---|---|
項目主頁 | https://github.com/zq2599/blog_demos | 該項目在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該項目源碼的倉庫地址,https協議 |
git倉庫地址(ssh) | git@github.com:zq2599/blog_demos.git | 該項目源碼的倉庫地址,ssh協議 |
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <modules> <module>simplebean</module> <!-- <module>testenvironment</module> --> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.bolingcavalry</groupId> <artifactId>junitpractice</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version> </dependency> </dependencies> </dependencyManagement> </project>
接下來我們準備一個簡單的SpringBoot工程用於作單元測試,該工程有service和controller層,包含一些簡單的接口和類;
<?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>com.bolingcavalry</groupId> <artifactId>junitpractice</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <groupId>com.bolingcavalry</groupId> <artifactId>junit5experience</artifactId> <version>0.0.1-SNAPSHOT</version> <name>junit5experience</name> <description>Demo project for simplebean in Spring Boot junit5</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
package com.bolingcavalry.junit5experience.service; public interface HelloService { String hello(String name); int increase(int value); /** * 該方法會等待1秒後返回true,這是在模擬一個耗時的遠程調用 * @return */ boolean remoteRequest(); }
package com.bolingcavalry.junit5experience.service.impl; import com.bolingcavalry.junit5experience.service.HelloService; import org.springframework.stereotype.Service; @Service() public class HelloServiceImpl implements HelloService { @Override public String hello(String name) { return "Hello " + name; } @Override public int increase(int value) { return value + 1; } @Override public boolean remoteRequest() { try { Thread.sleep(1000); } catch (InterruptedException interruptedException) { interruptedException.printStackTrace(); } return true; } }
package com.bolingcavalry.junit5experience.controller; import com.bolingcavalry.junit5experience.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired private HelloService helloService; @RequestMapping(value = "/{name}", method = RequestMethod.GET) public String hello(@PathVariable String name){ return helloService.hello(name); } }
package com.bolingcavalry.junit5experience; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Junit5ExperienceApplication { public static void main(String[] args) { SpringApplication.run(Junit5ExperienceApplication.class, args); } }
2. 測試類的內容以下,涵蓋了剛纔提到的經常使用註解,請注意每一個方法的註釋說明:
package com.bolingcavalry.junit5experience.service.impl; import com.bolingcavalry.junit5experience.service.HelloService; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest @Slf4j class HelloServiceImplTest { private static final String NAME = "Tom"; @Autowired HelloService helloService; /** * 在全部測試方法執行前被執行 */ @BeforeAll static void beforeAll() { log.info("execute beforeAll"); } /** * 在全部測試方法執行後被執行 */ @AfterAll static void afterAll() { log.info("execute afterAll"); } /** * 每一個測試方法執行前都會執行一次 */ @BeforeEach void beforeEach() { log.info("execute beforeEach"); } /** * 每一個測試方法執行後都會執行一次 */ @AfterEach void afterEach() { log.info("execute afterEach"); } @Test @DisplayName("測試service層的hello方法") void hello() { log.info("execute hello"); assertThat(helloService.hello(NAME)).isEqualTo("Hello " + NAME); } /** * DisplayName中帶有emoji,在測試框架中可以展現 */ @Test @DisplayName("測試service層的increase方法\uD83D\uDE31") void increase() { log.info("execute increase"); assertThat(helloService.increase(1)).isEqualByComparingTo(2); } /** * 不會被執行的測試方法 */ @Test @Disabled void neverExecute() { log.info("execute neverExecute"); } /** * 調用一個耗時1秒的方法,用Timeout設置超時時間是500毫秒, * 所以該用例會測試失敗 */ @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 500) @Disabled void remoteRequest() { assertThat(helloService.remoteRequest()).isEqualTo(true); } }
4. 以下圖,在彈出的菜單中,點擊紅框位置:
微信搜索「程序員欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos