SpringBoot | 第十三章:測試相關(單元測試、性能測試)

前言

前面寫了這麼多章節,都是經過瀏覽器訪問的形式,進行接口方法訪問進而驗證方法的正確與否。顯然在服務或者接口比較少時,這麼作沒有啥問題,但一旦一個項目稍微複雜或者接口方法比較多時,這麼驗證就有點不符合程序猿的懶人的特性了。因此這章節,講述下SpringBoot中的單元測試及基於Contiperf壓測工具進行性能測試相關方面的知識點。html

單元測試

是指對軟件中的最小可測試單元進行檢查和驗證。通常上在開發階段或者程序發佈時,都會利用像Maven這樣的打包工具進行打包前的測試,避免沒必要要的bug程序被打包部署。java

題外話:在開發階段,都應該要求編寫單元測試,核心的模塊還須要進行覆蓋測試,覆蓋率至少要95%以上。git

SpringBoot的單元測試

對於java開發者而言,Junit應該無人不知了。因此SpringBoot也是基於Junit進行單位測試的。github

0.加入pom依賴。web

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

1.這裏爲了演示,編寫了一個簡單的測試接口及編寫對應的測試類。spring

UnitTestService.javaapi

/**
 * 測試接口類
 * @author oKong
 *
 */
public interface UnitTestService {
    
    public String process(String msg);

}

實現類:UnitTestServiceImpl.java瀏覽器

@Service
public class UnitTestServiceImpl implements UnitTestService{

    /**
     * 爲了測試,這裏直接返回傳入的值
     */
    @Override
    public String process(String msg) {
        // TODO Auto-generated method stub
        return msg;
    }
}

測試類:UnitTestServiceTest.javaspringboot

題外話:我的建議,每一個測試類都應該和對應的被測試類包路徑一致。同時測試類的名稱是被測試的類名+Test,如本例所示的:微信

示例

/**
 * 編寫接口測試類
 * @author oKong
 *
 */
@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
@SpringBootTest 
public class UnitTestServiceTest {
    
    @Autowired
    UnitTestService testService;
    
    public void test() {
        String msg = "this is a test";
        String result = testService.process(msg);
        //斷言 是否和預期一致
        Assert.assertEquals(msg, result);
    }
}
  1. 運行右擊,選擇 run As --> Junit Test 或者須要debug時,選擇Debug As --> Junit Test,運行便可。

測試結果

3.至此,一個簡單的單元測試就結束了。**簡單來講,寫一個單元測試是容易的,但寫好一個單元測試是難的。**畢竟,每一個程序猿都以爲本身的代碼是沒有問題的,難道不是嗎?哈哈!

RESTful API 單元測試

對於服務類而言,編寫單元測試是相對簡單的,只須要像控制層自動引入接口類同樣。但編寫控制層即RESTful API 單元測試時,通常上就須要利用Mock技術進行測試了。固然也可使用像Swagger或者PostMan這樣的api測試工具進行測試(或者使用RestTemplate測試也是可行的),它可進行自動化測試,關於Postman會在以後的章節進行更新,做者也沒有過多研究過,也只是用到了它的最基本的發起http請求的功能,以後會整理相關資料的。

0.建立一個RESTful接口服務。

/**
 * 編寫mock測試服務
 * @author oKong
 *
 */
@RestController
public class DemoController {

    @GetMapping("/mock")
    public String demo(String msg) {
        return msg;
    }
}

1.編寫對應測試類

@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
//由於是mock測試,在實際開發過程當中,可指定其測試啓動時爲隨機端口,避免了沒必要要的端口衝突。
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 
//測試單一接口時 ,也可利用註解@WebMvcTest 進行單一測試
//@WebMvcTest(DemoController.class)
public class DemoControllerTest {

    //使用 WebMvcTest 時使用 
    //@autowired mockMvc 是可自動注入的。
    //當直接使用SpringBootTest 會提示 注入失敗  這裏直接示例利用 MockMvcBuilders工具建立
    //@Autowired
    MockMvc mockMvc;
    
    @Autowired
    WebApplicationContext wc;
    
    @Before
    public void beforeSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wc).build();
    }
    
    @Test
    public void testDemo() throws Exception {
        String msg = "this is a mock test";
        MvcResult result = this.mockMvc.perform(get("/mock").param("msg", msg)).andDo(print()).andExpect(status().isOk())
        .andReturn();
        
        //斷言 是否和預期相等
        Assert.assertEquals(msg, result.getResponse().getContentAsString());

    }
}

2.運行右擊,選擇 run As --> Junit Test 或者須要debug時,選擇Debug As --> Junit Test,運行便可。(也能夠看見每次啓動測試時,每次端口號都是不一樣的。)

2018-07-25 23:16:28.733  INFO 13000 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 59999 (http)
2018-07-25 23:16:28.754  INFO 13000 --- [           main] c.l.l.s.c.controller.DemoControllerTest  : Started DemoControllerTest in 5.673 seconds (JVM running for 6.769)

測試結果

因爲配置了print()這個ResultHandler,因此控制檯會打印相關參數信息。建議設置此屬性,這樣就算測試有問題,也能看下具體的參數信息。其餘相關mock的用法,此處就不舉例了,你們可自行搜索下,比較本章節只是簡單示例下用法~

請求參數信息

  1. 鑑於每次編寫控制層測試類時,都須要建立MockMvc對象,故可建立一個基類,這樣免得每次都寫。

BaseMockTest.java

/**
 * mock 基類
 * @author oKong
 *
 */
public abstract class BaseMockTest {
    
    @Autowired
    private WebApplicationContext wc;

    protected MockMvc mockMvc;
    
    @Before
    public void beforeSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wc).build();
    }

}

這樣編寫mock測試類時,還須要繼承此基類便可。

Junit經常使用註解說明

  • @Test 加在待測試的方法前面
  • @Before 帶上@Test的方法執行前會執行該方法
  • @After 帶上@Test的方法執行完畢後會執行該方法
  • @BeforeClass 加上這個註解,則該方法會第一個執行(在全部方法中),且方法要加上關鍵詞static,是一個static方法
  • @AfterClass 加上這個註解,則該方法最後一個執行(在全部方法中),一樣,方法要加上關鍵詞static,是一個static方法

詳細的使用,你們可自行谷歌下,畢竟經常使用的也就前面三個了,(┬_┬)

基於ContiPerf的性能測試

ContiPerf是一個輕量級的測試工具,基於JUnit 4 開發,可用於效率測試等。能夠指定在線程數量和執行次數,經過限制最大時間和平均執行時間來進行性能測試。

性能測試示例

0.加入pom依賴包。

<dependency>
            <groupId>org.databene</groupId>
            <artifactId>contiperf</artifactId>
            <version>2.3.4</version>
            <scope>test</scope>
        </dependency>

1.改寫UnitTestServiceTest測試類,進入ContiPerfRule題外話:@RuleJunit提供的一個擴展接口註解,其接口類爲:org.junit.rules.MethodRule,注意在Junit5中,已經被TestRule因此替代了。這裏只是簡單提下,由於具體的也不是很清楚,也沒有深刻了解過。

/**
 * 編寫接口測試類
 * @author oKong
 *
 */
@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
@SpringBootTest 
public class UnitTestServiceTest {
	
	@Autowired
	UnitTestService testService;
	
	//引入 ContiPerf 進行性能測試
	@Rule
	public ContiPerfRule contiPerfRule = new ContiPerfRule();
	
	@Test
	//10個線程 執行10次
	@PerfTest(invocations = 100,threads = 10)
	public void test() {
		String msg = "this is a test";
		String result = testService.process(msg);
		//斷言 是否和預期一致
		Assert.assertEquals(msg, result);
	}
}
  1. 控制檯會有性能報告,同時訪問:target/contiperf-report/index.html,會有圖表提示。

控制檯輸出:

cn.lqdev.learning.springboot.chapter13.service.UnitTestServiceTest.test
samples: 100
max:     403
average: 41.5
median:  15

測試報告:

測試報告

註解參數說明

@PerfTest

  • invocations:執行次數n,與線程數量無關,默認值爲1
  • threads:線程池數量n,併發執行n個線程
  • duration:重複地執行時間n,測試至少執行n毫秒

@Required

  • throughput:吞吐要求n,要求每秒至少執行n個測試
  • average:平均執行時間n,要求平均執行時間不超過n毫秒
  • max:最大執行時間n,要求最大的執行時間不超過n毫秒
  • totalTime:總執行時間n,要求總的執行時間不超過n毫秒
  • median:50%平均執行時間n,要求全部執行的50%測試平均執行時間不超過n毫秒
  • percentile90:90%平均執行時間n,要求全部執行的90%測試平均執行時間不超過n毫秒
  • percentile95:95%平均執行時間n,要求全部執行的95%測試平均執行時間不超過n毫秒
  • percentile99:99%平均執行時間n,要求全部執行的99%測試平均執行時間不超過n毫秒
  • percentiles:表達式"a:n,b:m",要求a%的測試不超過n毫秒,b%的測試不超過m毫秒

總結

本章節主要是對JunitContiPerf的使用簡單的示例,像MockMvc的詳細用法並無深刻,你們可自行搜索下,畢竟我也用的很少呀。

最後

目前互聯網上不少大佬都有SpringBoot系列教程,若有雷同,請多多包涵了。本文是做者在電腦前一字一句敲的,每一步都是實踐的。若文中有所錯誤之處,還望提出,謝謝。

老生常談

  • 我的QQ:499452441
  • 微信公衆號:lqdevOps

公衆號

我的博客:https://blog.lqdev.cn

完整示例:chapter-13

相關文章
相關標籤/搜索