(點選上方公眾號,可快速關註)
來源: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技能