實(shí)踐Jenkins集成Cobertura自動(dòng)化構(gòu)建SpringBoot工程

文章摘要:追求代碼質(zhì)量一直都是優(yōu)秀程序員對(duì)自己的目標(biāo),那么有什么好方法能夠?qū)崿F(xiàn)這個(gè)目標(biāo)?

在每個(gè)系統(tǒng)上線正式發(fā)布之前,開發(fā)同事對(duì)其中功能點(diǎn)進(jìn)行自測,測試同事根據(jù)前期設(shè)計(jì)的測試用例進(jìn)行功能測試的都是保障系統(tǒng)可靠穩(wěn)定運(yùn)行的重要前提。但是,系統(tǒng)上線后故障還偶有發(fā)生,那么如何才能將系統(tǒng)代碼質(zhì)量提高一個(gè)檔次做到上線后0故障的目標(biāo)呢?我想這個(gè)問題一直是許多研發(fā)同學(xué)和測試同學(xué)共同追求的一個(gè)目標(biāo),但光靠代碼review、簡單的自測和功能測試用例覆蓋還是不夠,需要從代碼覆蓋率(包括語句覆蓋率、分支覆蓋率和路徑覆蓋率等)的角度來解決。因此,本文從解決問題的根本原因出發(fā)介紹以SpringBoot工程的自動(dòng)化單元測試用例結(jié)合Cobetura插件來實(shí)現(xiàn)定時(shí)跑測試任務(wù)并生成測試報(bào)告。

一、代碼質(zhì)量與單元測試

追求代碼質(zhì)量是一個(gè)優(yōu)秀程序員對(duì)自我的要求。我們寫一段代碼、一個(gè)方法和一個(gè)類,不僅僅說完成了編碼,保證代碼能正常得跑起來就行了,而且也必須使得代碼是優(yōu)雅和干凈的。一般來說正常的情況大家都能考慮到,比較關(guān)鍵和重要的是,我們?cè)趯懘a時(shí)除了能夠執(zhí)行正常業(yè)務(wù)邏輯以外,還要能考慮和覆蓋到各種不同的異常情況。我想在編碼時(shí)候,考慮正常和異常情況的時(shí)間分配比例應(yīng)該是30%:70%。

從主觀上來說,代碼質(zhì)量一般是跟程序員的專業(yè)技能熟練度,比如編程語言(C++/Java/go等)、技術(shù)框架(Spring/Dubbo/Spring Cloud/Spring Boot等)、設(shè)計(jì)模式(工廠/抽象/代理模式等),成正比的。但是,對(duì)于極為優(yōu)秀的程序員來說即使能夠盡可能地確保自己的千行代碼沒有缺陷,卻不一定能夠保證幾萬行都沒有任何缺陷。所以,我們需要借鑒其他的方法來提高自己的代碼質(zhì)量,盡可能少地讓潛在的問題暴露在生產(chǎn)環(huán)境上。

增加功能測試用例和接口單元測試都是能夠提高代碼質(zhì)量的方式,各有優(yōu)劣。本文從編程者的角度出發(fā),更加注重的是代碼覆蓋測試,畢竟只有寫代碼的人才能更容易地把控代碼中的業(yè)務(wù)邏輯,能夠更好的編寫單元測試用例以覆蓋正常和異常的業(yè)務(wù)場景。

在做單元接口測試時(shí),代碼覆蓋率常常是被拿來作為衡量測試好壞的指標(biāo),甚至,用代碼覆蓋率來考核測試任務(wù)完成情況。通常來說,我們會(huì)關(guān)注方法覆蓋、語句覆蓋、條件覆蓋和分支覆蓋這幾種度量方式。

二、Spring Boot工程的代碼單元測試

本文第一節(jié)主要都是講了理論,相對(duì)比較枯燥。下面這一節(jié)將從實(shí)踐的角度,來一步一步向大家展示如何在Spring Boot工程中對(duì)業(yè)務(wù)代碼寫單元測試用例。

1、版本環(huán)境

Spring Boot 1.4.1.RELEASE、JDK1.8

2、Spring Boot工程引入單元測試

在Spring Boot工程中引入單元測試比較簡單,只需要簡單地在pom文件中引入依賴如下:

在工程中引入spring-boot-starter-test后,就會(huì)有如下幾個(gè)庫:

(a)JUnit:Java語言的單元測試框架;

(b)SpringTest & Spring Boot Test:為Spring Boot程序提供集成測試的工具;

(c)AssertJ:?一種斷言庫;

(d)Hamcrest:也是一種斷言庫,不過更新頻度較慢;

(e)Mockito?:Java程序Mock測試的框架;

(f)JsonPath?:Xpath在Json中的應(yīng)用庫;

(g)JSONassert:Json的斷言庫;

spring-boot-starter-test的pom依賴圖如下:

3、工程中Service/Dao的單元測試

對(duì)于Spring Boot工程中的Service/Dao層的類來說,創(chuàng)建其單元測試方法比較簡單,直接手動(dòng)創(chuàng)建即可。

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest(classes? = OpHuaweiAgentApplication.class)

@Slf4j

public? class VmServiceTest {

??? private ObjectMapper mapper = new? ObjectMapper();

??? private static final String? JSON_CREATE_VM_REQUEST = "/vm/createVmReq.json";

??? @Autowired

? private VmService vmService;

?? ?@Before

??? public void setUp() throws Exception {

??????? //測試用例數(shù)據(jù)準(zhǔn)備

?????????????????? //code here

??? }

??? @Test

??? public void create() throws Exception {

??????? String createBody =? getResource(JSON_CREATE_VM_REQUEST);

??????? JSONObject body =? JSONObject.parseObject(createBody);

??????? HwTokenWrapper token =? getDomainToken();

??????? String projectId =? token.getToken().getProject().getId();

??????? CreateJobRespDto respDto =? vmService.create(token.getId(), projectId, body);

??????? assertTrue(null !=? respDto.getJobId());

??????? log.debug("create vm job創(chuàng)建成功,jobId:{}",? respDto);

??? }

???????? @After

???????? public void cleanUp() throws? Exception(){

?????????????????? //測試數(shù)據(jù)清理

?????????????????? //code here

???????? }

如上面的對(duì)Service層的單元測試用例代碼可見,在帶有@Before注解的方法setUp中完成對(duì)測試用例的數(shù)據(jù)準(zhǔn)備,可以提前在測試環(huán)境數(shù)據(jù)庫中插入測試用例所需依賴的測試局?jǐn)?shù)據(jù)。在@Test注解的方法—create是單元測試真正執(zhí)行的方法,示例中使用提前組織好的創(chuàng)建主機(jī)規(guī)格的Json數(shù)據(jù)作為參數(shù)調(diào)用被測試的Service層的VmService方法,執(zhí)行創(chuàng)建主機(jī)的驗(yàn)證。同時(shí)使用斷言機(jī)制,來判斷返回結(jié)果是否跟預(yù)期的一致。其中,準(zhǔn)備好的Json數(shù)據(jù)放在SpringBoot工程的src/test/resources下面。最后在,@After注解的方法cleanUp下執(zhí)行提前插入數(shù)據(jù)的回滾和清理。

4、工程中Controller Api的單元測試

對(duì)Service/Dao層的類進(jìn)行接口單元測試還是比較簡便的。然而,一般的SpringBoot工程都需要對(duì)外部提供Api接口,因此有必要對(duì)Controller層進(jìn)行單元測試以保證控制器執(zhí)行的業(yè)務(wù)邏輯正確,這時(shí)候就得用到MockMvc了。使用MockMvc可以使得開發(fā)或者測試不必再借助postman這種Http調(diào)試工具進(jìn)行手動(dòng)測試,既提高測試的效率,也能夠反復(fù)跑單元測試用例來進(jìn)行回歸驗(yàn)證。

Spring Test框架中的MockMvc實(shí)現(xiàn)了對(duì)Http請(qǐng)求的模擬,能夠直接通過網(wǎng)絡(luò)的形式,轉(zhuǎn)換到Controller層的Api調(diào)用,這樣在提高測試效率的同時(shí)可以不依賴外部環(huán)境。

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest(classes? = OpHuaweiAgentApplication.class)

@WebAppConfiguration

@Slf4j

public? class OrderManageControllerTest extends AbstractTest {

???????? //此處API URL為示例代碼

??? public static final String? GENERATE_ORDERID_API_URL = "/rest/xxxxxxxxx";

???????? //此處為鑒權(quán)的Json測試數(shù)據(jù)

???????? private static final String? JSON_AUTH_TOKEN_REQ = "/api/order/authTokenReq.json";

??? @Autowired

??? private WebApplicationContext context;

??? private MockMvc mvc;

??? @Before

??? public void setUp() {

?????????????????? //測試用例數(shù)據(jù)準(zhǔn)備

?????????????????? //code here

??????? this.mvc =? MockMvcBuilders.webAppContextSetup(this.context).build();

??? }

??? @Test

??? public void generateOrderIdTest() throws? Exception {

??????? JSONObject jsonObject = JSONObject.parseObject(getResource(JSON_AUTH_TOKEN_REQ));

??????? MockHttpServletRequestBuilder builder? = post(GENERATE_ORDERID_API_URL). header("X-Auth-Token",? jsonObject.getString("token"));

MvcResult result =? mvc.perform(builder).andReturn();

assertEquals(HttpStatus.OK.value(),? result.getResponse().getStatus());

}

???????? @After

???????? public void cleanUp() throws? Exception(){

?????????????????? //測試數(shù)據(jù)清理

?????????????????? //code here

???????? }

從上面對(duì)Controller層Api接口的單元測試示例代碼可見,在帶有@Before注解的setUp方法中,通過MockMvcBuilders工具類使用注入的WebApplicationContext上下文對(duì)象創(chuàng)建MockMvc對(duì)象。這里,MockMvc對(duì)象提供一組工具函數(shù)用來執(zhí)行assert判斷,都是針對(duì)web請(qǐng)求的判斷。這組工具的使用方式是函數(shù)的鏈?zhǔn)秸{(diào)用,允許程序員將多個(gè)測試用例鏈接在一起,并進(jìn)行多個(gè)判斷。在帶有@Test注解的generateOrderIdTest測試方法中,先加載提前準(zhǔn)備好的鑒權(quán)請(qǐng)求JsonObject對(duì)象,然后MockMvc對(duì)象執(zhí)行相應(yīng)的post請(qǐng)求,其中參數(shù)為帶有Header頭的MockHttpServletRequestBuilder對(duì)象。最后,通過assertEquals斷言機(jī)制來確認(rèn)接口返回是否為Http響應(yīng)的正確編碼(200)。如同之前的一樣,@After注解的方法cleanUp下執(zhí)行提前插入數(shù)據(jù)的回滾和清理。

三、Spring Boot工程集成Cobetura插件

通過上面的內(nèi)容,可以在Spring Boot工程中完成對(duì)Controller/Service/Dao層的添加單元測試用例,但僅限于此只能通過單元測試用例的結(jié)果(是否跑成功)來判斷用例正確與否,而無法來判斷測試的其他度量指標(biāo),比如本文前面提到的方法覆蓋、語句覆蓋、條件覆蓋和分支覆蓋等。因此,這節(jié)通過引入第三方組件—Cobertura來完成這一目標(biāo)。

Cobertura 是一種開源的代碼覆蓋率檢測工具,它通過檢測基本的代碼,并觀察在測試包運(yùn)行時(shí)執(zhí)行了哪些代碼和沒有執(zhí)行哪些代碼,并最終以html或者xml的格式來呈現(xiàn)最終測試的度量指標(biāo)結(jié)果(比如分支覆蓋率和代碼行覆蓋率)。

1、Spring Boot工程的pom文件中添加Cobertura插件

在Spring Boot工程的pom文件中添加Cobertuar插件的配置如下:



2、運(yùn)行Coberuta插件生成測試報(bào)告

在Spring Boot工程目錄下執(zhí)行以下maven命令—“mvn cobertura:cobertura”,執(zhí)行完后會(huì)在target目錄里找到site目錄,用瀏覽器打開里面的index.html,這就是測試用例執(zhí)行完后cobertura-maven-plugin得出的覆蓋率報(bào)告。如圖下所示:



四、Cobertura與自動(dòng)化構(gòu)建工具Jenkins的集成

僅在本地對(duì)Spring Boot工程執(zhí)行Cobertura的maven命令,并不能很好的實(shí)現(xiàn)自動(dòng)持續(xù)集成的目標(biāo)。這一節(jié)主要將介紹如何在Jenkins工具中一步步集成Cobertura插件并完成Spring Boot工程的代碼覆蓋率測試報(bào)告輸出。

1、首先需要在Jenkins工具上完成Cobertura插件的安裝。


2、配置jenkins工具,修改maven的執(zhí)行命令,這里主要是添加cobertura執(zhí)行命令clean cobertura:cobertura package。


3、在Add post build action這個(gè)配置項(xiàng)中選擇如下Publish Cobertura Coverage Report:


4、這一步中需要選擇一個(gè)配置項(xiàng),該配置項(xiàng)目是最終cobertura生成xml/html report的路徑,在示例中的路徑為**/target/site/cobertura/coverage.xml。


5、最后,重新build該項(xiàng)目,即可在項(xiàng)目中看到本工程代碼覆蓋率的測試用例報(bào)告了:


五、總結(jié)

本文從代碼質(zhì)量與單元測試用例方面切入,先介紹了如何在Spring Boot工程中完成各層(Controller Api/Service/Dao層)的接口單元白盒測試,隨后介紹了如何在Spring Boot工程中集成Cobertura插件,并利用Jenkins工具進(jìn)行自動(dòng)化持續(xù)集成以產(chǎn)生代碼覆蓋率的測試報(bào)告。限于筆者的才疏學(xué)淺,對(duì)本文內(nèi)容可能還有理解不到位的地方,如有闡述不合理之處還望留言一起探討。

個(gè)人專屬的公眾號(hào)(匠心獨(dú)運(yùn)的博客),歡迎關(guān)注一起交流和學(xué)習(xí)二維碼如下:


匠心獨(dú)運(yùn)的博客
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,254評(píng)論 6 342
  • 在天橋,我與曾經(jīng)的自己并肩走著; 夜很黑,但有微黃的夜燈打著前方的路; 我看著她,一身校服,兩撮馬尾,輕盈活潑; ...
    遇見you時(shí)閱讀 310評(píng)論 0 1
  • 也是寫給我自己的,不逼逼,直入正題。 最近在給家里的小工作坊招聘工人。強(qiáng)烈感覺到招聘真的需要成本,最基本的,在各個(gè)...
    我的天啊東西閱讀 303評(píng)論 0 0
  • 性能測試是什么:性能測試就是通過特定的方式對(duì)被測試系統(tǒng)按照一定測試策略施加壓力,獲取該系統(tǒng)的響應(yīng)時(shí)間、TPS、吞吐...
    花開沉浮閱讀 4,649評(píng)論 0 4

友情鏈接更多精彩內(nèi)容