Spring Boot 單元測試示例


Spring 框架提供了一個專門的測試模塊(spring-test),用於應用程序的單元測試。 在 Spring Boot 中,你可以通過spring-boot-starter-test啟動器快速開啟和使用它。

在pom.xml文件中引入maven依賴:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

1. JUnit單元測試

當你的單元測試代碼不需要用到 Spring Boot 功能,而只是一個簡單的測試時,你可以直接編寫你的 Junit 測試代碼:

public class SimpleJunitTest {

@Test

public void testSayHi() {

System.out.println("Hi Junit.");

}

}

2. Spring Boot單元測試

當你的集成測試代碼需要用到 Spring Boot 功能時,你可以使用@SpringBootTest注解。該注解是普通的 Spring 項目(非 Spring Boot 項目)中編寫集成測試代碼所使用的@ContextConfiguration注解的替代品。其作用是用於確定如何裝載 Spring 應用程序的上下文資源。

@RunWith(SpringRunner.class)

@SpringBootTest

public class BeanInjectTest {

@Autowired

private HelloService helloService;

@Test

public void testSayHi() {

System.out.println(helloService.sayHi());

}

}

@Service

public class HelloService {

public String sayHi() {

return "--- Hi ---";

}

public String sayHello() {

return "--- Hello ---";

}

}

當運行 Spring Boot 應用程序測試時,它會自動的從當前測試類所在的包起一層一層向上搜索,直到找到一個@SpringBootApplication或@SpringBootConfiguration注釋類為止。以此來確定如何裝載 Spring 應用程序的上下文資源。

主配置啟動類的代碼為:

@SpringBootApplication

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class);

}

}

如果搜索算法搜索不到你項目的主配置文件,將報出異常:

java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=…) with your test

解決辦法是,按 Spring Boot 的約定重新組織你的代碼結構,或者手工指定你要裝載的主配置文件:

@RunWith(SpringRunner.class)

@SpringBootTest(classes = {YourApplication.class})

public class BeanInjectTest {

// ...

}

基於 Spring 環境的 Junit 集成測試還需要使用@RunWith(SpringJUnit4ClassRunner.class)注解,該注解能夠改變 Junit 並讓其運行在 Spring 的測試環境,以得到 Spring 測試環境的上下文支持。否則,在 Junit 測試中,Bean 的自動裝配等注解將不起作用。但由於 SpringJUnit4ClassRunner 不方便記憶,Spring 4.3 起提供了一個等同於 SpringJUnit4ClassRunner 的類 SpringRunner,因此可以簡寫成:@RunWith(SpringRunner.class)。

3. Spring MVC 單元測試

當你想對 Spring MVC 控制器編寫單元測試代碼時,可以使用@WebMvcTest注解。它提供了自配置的 MockMvc,可以不需要完整啟動 HTTP 服務器就可以快速測試 MVC 控制器。

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)

@WebMvcTest(HelloController.class)

public class HelloControllerTest {

@Autowired

private MockMvc mvc;

@Test

public void testHello() throws Exception {

mvc.perform(get("/hello"))

.andExpect(status().isOk())

.andDo(print());

}

}

@Controller

public class HelloController {

@GetMapping("/hello")

public String hello(ModelMap model) {

model.put("message", "Hello Page");

return "hello";

}

}

使用@WebMvcTest注解時,只有一部分的 Bean 能夠被掃描得到,它們分別是:

@Controller

@ControllerAdvice

@JsonComponent

Filter

WebMvcConfigurer

HandlerMethodArgumentResolver

其他常規的@Component(包括@Service、@Repository等)Bean 則不會被加載到 Spring 測試環境上下文中。

如果測試的 MVC 控制器中需要@ComponentBean 的參與,你可以使用@MockBean注解來協助完成:

import static org.mockito.BDDMockito.*;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)

@WebMvcTest(HelloController.class)

public class HelloControllerTest {

@Autowired

private MockMvc mvc;

@MockBean

private HelloService helloService;

@Test

public void testSayHi() throws Exception {

// 模擬 HelloService.sayHi() 調用, 返回 "=== Hi ==="

when(helloService.sayHi()).thenReturn("=== Hi ===");

mvc.perform(get("/hello/sayHi"))

.andExpect(status().isOk())

.andDo(print());

}

}

@Controller

public class HelloController {

@Autowired

private HelloService helloService;

@GetMapping("/hello/sayHi")

public String sayHi(ModelMap model) {

model.put("message", helloService.sayHi());

return "hello";

}

}

 

Controller的mock單元測試的另一種方法:

package net.mingsoft.mdiy.action;

import net.mingsoft.MSApplication;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebAppConfiguration
@RunWith(SpringRunner.class)
//使用隨機端口
@SpringBootTest(classes = {MSApplication.class})// 指定啟動類
public class ArticleActionMockTest {

    @Autowired private WebApplicationContext wac; private MockMvc mvc;

    @Before public void setUp() { mvc = MockMvcBuilders.webAppContextSetup(wac).build(); } 
    @Test
    public void testGetMdiyForm() throws Exception{
        this.mvc.perform(get("/ms/mdiy/contentModel/form")).andExpect(status().isOk())
                .andDo(MockMvcResultHandlers.print());

    }



}

 

 

 

4. Spring Boot Web 單元測試

當你想啟動一個完整的 HTTP 服務器對 Spring Boot 的 Web 應用編寫測試代碼時,可以使用@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)注解開啟一個隨機的可用端口。Spring Boot 針對 REST 調用的測試提供了一個 TestRestTemplate 模板,它可以解析鏈接服務器的相對地址。

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)

public class ApplicationTest {

@Autowired

private TestRestTemplate restTemplate;

@Test

public void testSayHello() {

Map result = restTemplate.getForObject("/hello/sayHello", Map.class);

System.out.println(result.get("message"));

}

}

@Controller

public class HelloController {

@Autowired

private HelloService helloService;

@GetMapping("/hello/sayHello")

public @ResponseBody Object helloInfo() {

Map map = new HashMap<>();

map.put("message", helloService.sayHello());

return map;

}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM