javascript
使用JUnit 5进行Spring Boot测试
JUnit 5 (JUnit Jupiter)已經(jīng)存在了相當(dāng)長的一段時間,并且配備了許多功能。 但令人意外JUnit 5它不是一個默認(rèn)的測試庫相關(guān),當(dāng)涉及到春節(jié)開機測試入門:它仍然是JUnit 4.12 ,在2014年發(fā)布了回來,如果你考慮使用JUnit 5對你未來基于Spring啟動項目,然后這篇博客文章是給你的。 您將通過針對不同用例的Spring Boot測試示例,了解基于Gradle和Maven的項目的基本設(shè)置。
源代碼
可以在Github上找到本文的源代碼: https : //github.com/kolorobot/spring-boot-junit5 。
從頭開始設(shè)置項目
對于項目設(shè)置,您將需要JDK 11或更高版本以及Gradle或Maven(取決于您的偏好)。 開始使用Spring Boot的最簡單方法是使用https://start.spring.io上的Initializr。 選擇的唯一依賴項是Spring Web 。 無論您在生成的項目中使用什么依賴項,始終都包含測試依賴項( Spring Boot Starter Test )。
用Gradle構(gòu)建
使用Initializr生成的Gradle構(gòu)建的默認(rèn)項目文件( gradle.build ):
plugins { id 'org.springframework.boot' version '2.1.8.RELEASE' id 'io.spring.dependency-management' version '1.0.8.RELEASE' id 'java' } group = 'pl.codeleak.samples' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' }為了增加對JUnit 5支持,我們需要排除舊的JUnit 4依賴性,并包括JUnit 5 (JUnit Jupiter)依賴性:
dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation( 'org.springframework.boot:spring-boot-starter-test' ) { exclude group: 'junit' , module: 'junit' } testCompile 'org.junit.jupiter:junit-jupiter:5.5.2' } test { useJUnitPlatform() testLogging { events "passed" , "skipped" , "failed" } }用Maven構(gòu)建
使用Initializr生成的Maven構(gòu)建的默認(rèn)項目文件( pom.xml ):
<? xml version = "1.0" encoding = "UTF-8" ?> < project > < modelVersion >4.0.0</ modelVersion > < parent > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-parent</ artifactId > < version >2.1.8.RELEASE</ version > < relativePath /> <!-- lookup parent from repository --> </ parent > < groupId >pl.codeleak.samples</ groupId > < artifactId >spring-boot-junit5</ artifactId > < version >0.0.1-SNAPSHOT</ version > < name >spring-boot-junit5</ name > < description >Demo project for Spring Boot and JUnit 5</ description > < properties > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < java.version >11</ java.version > </ properties > < dependencies > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-web</ artifactId > </ 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 >為了增加對JUnit 5支持,我們需要排除舊的JUnit 4依賴性,并包括JUnit 5 (JUnit Jupiter)依賴性:
< properties > < junit.jupiter.version >5.5.2</ junit.jupiter.version > </ properties > < dependencies > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-web</ artifactId > </ dependency > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-test</ artifactId > < scope >test</ scope > < exclusions > < exclusion > < groupId >junit</ groupId > < artifactId >junit</ artifactId > </ exclusion > </ exclusions > </ dependency > < dependency > < groupId >org.junit.jupiter</ groupId > < artifactId >junit-jupiter</ artifactId > < version >${junit.jupiter.version}</ version > < scope >test</ scope > </ dependency > </ dependencies >在測試類中使用JUnit 5
Initializr生成的測試包含自動生成的JUnit 4測試。 要應(yīng)用JUnit 5我們需要更改導(dǎo)入并將JUnit 4替換為JUnit 5擴展。 我們還可以使類和測試方法包受到保護:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; @ExtendWith (SpringExtension. class ) @SpringBootTest class SpringBootJunit5ApplicationTests { @Test void contextLoads() { } }提示:如果您不熟悉JUnit 5,請參閱我有關(guān)JUnit 5的其他文章: https : //blog.codeleak.pl/search/label/junit 5
運行測試
我們可以使用Maven Wrapper : ./mvnw clean test或Gradle Wrapper : ./gradlew clean test 。
源代碼
請咨詢此提交以獲取與項目設(shè)置相關(guān)的更改。
具有單個REST控制器的示例應(yīng)用程序
該示例應(yīng)用程序包含一個具有三個端點的REST控制器:
- /tasks/{id}
- /tasks
- /tasks?title={title}
控制器的每個方法都在內(nèi)部調(diào)用JSONPlaceholder –用于測試和原型制作的假在線REST API。
項目文件的結(jié)構(gòu)如下:
$ tree src/main/java src/main/java └── pl └── codeleak └── samples └── springbootjunit5 ├── SpringBootJunit5Application.java ├── config │ ├── JsonPlaceholderApiConfig.java │ └── JsonPlaceholderApiConfigProperties.java └── todo ├── JsonPlaceholderTaskRepository.java ├── Task.java ├── TaskController.java └── TaskRepository.java它還具有以下靜態(tài)資源:
$ tree src/main/resources/ src/main/resources/ ├── application.properties ├── static │ ├── error │ │ └── 404 .html │ └── index.html └── templatesTaskController將其工作委托給TaskRepository :
@RestController class TaskController { private final TaskRepository taskRepository; TaskController(TaskRepository taskRepository) { this .taskRepository = taskRepository; } @GetMapping ( "/tasks/{id}" ) Task findOne( @PathVariable Integer id) { return taskRepository.findOne(id); } @GetMapping ( "/tasks" ) List<Task> findAll() { return taskRepository.findAll(); } @GetMapping (value = "/tasks" , params = "title" ) List<Task> findByTitle(String title) { return taskRepository.findByTitle(title); } }TaskRepository由JsonPlaceholderTaskRepository實現(xiàn),該TaskRepository在內(nèi)部使用RestTemplate來調(diào)用JSONPlaceholder( https://jsonplaceholder.typicode.com )端點:
public class JsonPlaceholderTaskRepository implements TaskRepository { private final RestTemplate restTemplate; private final JsonPlaceholderApiConfigProperties properties; public JsonPlaceholderTaskRepository(RestTemplate restTemplate, JsonPlaceholderApiConfigProperties properties) { this .restTemplate = restTemplate; this .properties = properties; } @Override public Task findOne(Integer id) { return restTemplate .getForObject( "/todos/{id}" , Task. class , id); } // other methods skipped for readability }通過JsonPlaceholderApiConfig配置應(yīng)用程序,該配置JsonPlaceholderApiConfig使用JsonPlaceholderApiConfigProperties綁定來自application.properties一些明智的屬性:
@Configuration @EnableConfigurationProperties (JsonPlaceholderApiConfigProperties. class ) public class JsonPlaceholderApiConfig { private final JsonPlaceholderApiConfigProperties properties; public JsonPlaceholderApiConfig(JsonPlaceholderApiConfigProperties properties) { this .properties = properties; } @Bean RestTemplate restTemplate() { return new RestTemplateBuilder() .rootUri(properties.getRootUri()) .build(); } @Bean TaskRepository taskRepository(RestTemplate restTemplate, JsonPlaceholderApiConfigProperties properties) { return new JsonPlaceholderTaskRepository(restTemplate, properties); } }application.properties包含幾個與JSONPlaceholder端點配置有關(guān)的屬性:
json-placeholder.root-uri=https: //jsonplaceholder.typicode.com json-placeholder.todo-find-all.sort=id json-placeholder.todo-find-all.order=desc json-placeholder.todo-find-all.limit= 20在此博客文章中了解有關(guān)@ConfigurationProperties更多信息: https : //blog.codeleak.pl/2014/09/using-configurationproperties-in-spring.html
源代碼
請咨詢此提交以獲取與應(yīng)用程序源代碼相關(guān)的更改。
創(chuàng)建Spring Boot測試
Spring Boot提供了許多支持測試應(yīng)用程序的實用程序和注釋。
創(chuàng)建測試時可以使用不同的方法。 在下面,您將找到創(chuàng)建Spring Boot測試的最常見情況。
在隨機端口上運行Web服務(wù)器的Spring Boot測試
@ExtendWith (SpringExtension. class ) @SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class TaskControllerIntegrationTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Test void findsTaskById() { // act var task = restTemplate.getForObject( " http://localhost: " + port + "/tasks/1" , Task. class ); // assert assertThat(task) .extracting(Task::getId, Task::getTitle, Task::isCompleted, Task::getUserId) .containsExactly( 1 , "delectus aut autem" , false , 1 ); } }在具有模擬依賴項的隨機端口上運行Web服務(wù)器的Spring Boot測試
@ExtendWith (SpringExtension. class ) @SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class TaskControllerIntegrationTestWithMockBeanTest { @LocalServerPort private int port; @MockBean private TaskRepository taskRepository; @Autowired private TestRestTemplate restTemplate; @Test void findsTaskById() { // arrange var taskToReturn = new Task(); taskToReturn.setId( 1 ); taskToReturn.setTitle( "delectus aut autem" ); taskToReturn.setCompleted( true ); taskToReturn.setUserId( 1 ); when(taskRepository.findOne( 1 )).thenReturn(taskToReturn); // act var task = restTemplate.getForObject( " http://localhost: " + port + "/tasks/1" , Task. class ); // assert assertThat(task) .extracting(Task::getId, Task::getTitle, Task::isCompleted, Task::getUserId) .containsExactly( 1 , "delectus aut autem" , true , 1 ); } }帶有模擬MVC層的Spring Boot測試
@ExtendWith (SpringExtension. class ) @SpringBootTest @AutoConfigureMockMvc class TaskControllerMockMvcTest { @Autowired private MockMvc mockMvc; @Test void findsTaskById() throws Exception { mockMvc.perform(get( "/tasks/1" )) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().json( "{\"id\":1,\"title\":\"delectus aut autem\",\"userId\":1,\"completed\":false}" )); } }具有模擬的MVC層和模擬的依賴項的Spring Boot測試
@ExtendWith (SpringExtension. class ) @SpringBootTest @AutoConfigureMockMvc class TaskControllerMockMvcWithMockBeanTest { @Autowired private MockMvc mockMvc; @MockBean private TaskRepository taskRepository; @Test void findsTaskById() throws Exception { // arrange var taskToReturn = new Task(); taskToReturn.setId( 1 ); taskToReturn.setTitle( "delectus aut autem" ); taskToReturn.setCompleted( true ); taskToReturn.setUserId( 1 ); when(taskRepository.findOne( 1 )).thenReturn(taskToReturn); // act and assert mockMvc.perform(get( "/tasks/1" )) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().json( "{\"id\":1,\"title\":\"delectus aut autem\",\"userId\":1,\"completed\":true}" )); } }帶有模擬Web層的Spring Boot測試
@ExtendWith (SpringExtension. class ) @WebMvcTest @Import (JsonPlaceholderApiConfig. class ) class TaskControllerWebMvcTest { @Autowired private MockMvc mockMvc; @Test void findsTaskById() throws Exception { mockMvc.perform(get( "/tasks/1" )) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().json( "{\"id\":1,\"title\":\"delectus aut autem\",\"userId\":1,\"completed\":false}" )); } }具有模擬Web層和模擬依賴項的Spring Boot測試
@ExtendWith (SpringExtension. class ) @WebMvcTest class TaskControllerWebMvcWithMockBeanTest { @Autowired private MockMvc mockMvc; @MockBean private TaskRepository taskRepository; @Test void findsTaskById() throws Exception { // arrange var taskToReturn = new Task(); taskToReturn.setId( 1 ); taskToReturn.setTitle( "delectus aut autem" ); taskToReturn.setCompleted( true ); taskToReturn.setUserId( 1 ); when(taskRepository.findOne( 1 )).thenReturn(taskToReturn); // act and assert mockMvc.perform(get( "/tasks/1" )) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().json( "{\"id\":1,\"title\":\"delectus aut autem\",\"userId\":1,\"completed\":true}" )); } }運行所有測試
我們可以使用Maven Wrapper : ./mvnw clean test或Gradle Wrapper : ./gradlew clean test運行所有./gradlew clean test 。
使用Gradle運行測試的結(jié)果:
$ ./gradlew clean test > Task :test pl.codeleak.samples.springbootjunit5.SpringBootJunit5ApplicationTests > contextLoads() PASSED pl.codeleak.samples.springbootjunit5.todo.TaskControllerWebMvcTest > findsTaskById() PASSED pl.codeleak.samples.springbootjunit5.todo.TaskControllerIntegrationTestWithMockBeanTest > findsTaskById() PASSED pl.codeleak.samples.springbootjunit5.todo.TaskControllerWebMvcWithMockBeanTest > findsTaskById() PASSED pl.codeleak.samples.springbootjunit5.todo.TaskControllerIntegrationTest > findsTaskById() PASSED pl.codeleak.samples.springbootjunit5.todo.TaskControllerMockMvcTest > findsTaskById() PASSED pl.codeleak.samples.springbootjunit5.todo.TaskControllerMockMvcWithMockBeanTest > findsTaskById() PASSED BUILD SUCCESSFUL in 7s 5 actionable tasks: 5 executed參考文獻
- https://docs.spring.io/spring-boot/docs/2.1.8.RELEASE/reference/html/boot-features-testing.html
- https://spring.io/guides/gs/testing-web/
- https://github.com/spring-projects/spring-boot/issues/14736
翻譯自: https://www.javacodegeeks.com/2019/09/spring-boot-testing-junit-5.html
總結(jié)
以上是生活随笔為你收集整理的使用JUnit 5进行Spring Boot测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑不oa系统不能登录(无法登陆oa系统
- 下一篇: Spring@主要注释