歡迎光臨
每天分享高質量文章

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

(點擊上方公眾號,可快速關註)


來源:oKong ,

blog.lqdev.cn/2018/07/26/springboot/chapter-thirteen/

前言

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

單元測試

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

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

SpringBoot的單元測試

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

0.加入pom依賴。

    org.springframework.boot

    spring-boot-starter-test

    test

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

UnitTestService.java

/**

 * 測試接口類

 * @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.java

題外話:個人建議,每個測試類都應該和對應的被測試類包路徑一致。同時測試類的名稱是被測試的類名+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);

    }

}

 

2. 運行右擊,選擇 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的用法,此處就不舉例了,大家可自行搜索下,比較本章節只是簡單示例下用法~

3. 鑒於每次編寫控制層測試類時,都需要創建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依賴包。

    org.databene

    contiperf

    2.3.4

    test

1.改寫UnitTestServiceTest測試類,進入ContiPerfRule。

題外話:@Rule是Junit提供的一個擴展接口註解,其接口類為: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);

    }

}

 

2. 控制台會有性能報告,同時訪問: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毫秒

總結

本章節主要是對Junit和ContiPerf的使用簡單的示例,像MockMvc的詳細用法並沒有深入,大家可自行搜索下,畢竟我也用的不多呀。

最後

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

系列


【關於投稿】


如果大家有原創好文投稿,請直接給公號發送留言。


① 留言格式:
【投稿】+《 文章標題》+ 文章鏈接

② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/

③ 最後請附上您的個人簡介哈~



看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

赞(0)

分享創造快樂