实践Jenkins集成Cobertura自动化构建SpringBoot工程

文章摘要:追求代码质量一直都是优秀程序员对自己的目标,那么有什么好方法能够实现这个目标?

在每个系统上线正式发布之前,开发同事对其中功能点进行自测,测试同事根据前期设计的测试用例进行功能测试的都是保障系统可靠稳定运行的重要前提。但是,系统上线后故障还偶有发生,那么如何才能将系统代码质量提高一个档次做到上线后0故障的目标呢?我想这个问题一直是许多研发同学和测试同学共同追求的一个目标,但光靠代码review、简单的自测和功能测试用例覆盖还是不够,需要从代码覆盖率(包括语句覆盖率、分支覆盖率和路径覆盖率等)的角度来解决。因此,本文从解决问题的根本原因出发介绍以SpringBoot工程的自动化单元测试用例结合Cobetura插件来实现定时跑测试任务并生成测试报告。

一、代码质量与单元测试

追求代码质量是一个优秀程序员对自我的要求。我们写一段代码、一个方法和一个类,不仅仅说完成了编码,保证代码能正常得跑起来就行了,而且也必须使得代码是优雅和干净的。一般来说正常的情况大家都能考虑到,比较关键和重要的是,我们在写代码时除了能够执行正常业务逻辑以外,还要能考虑和覆盖到各种不同的异常情况。我想在编码时候,考虑正常和异常情况的时间分配比例应该是30%:70%。

从主观上来说,代码质量一般是跟程序员的专业技能熟练度,比如编程语言(C++/Java/go等)、技术框架(Spring/Dubbo/Spring Cloud/Spring Boot等)、设计模式(工厂/抽象/代理模式等),成正比的。但是,对于极为优秀的程序员来说即使能够尽可能地确保自己的千行代码没有缺陷,却不一定能够保证几万行都没有任何缺陷。所以,我们需要借鉴其他的方法来提高自己的代码质量,尽可能少地让潜在的问题暴露在生产环境上。

增加功能测试用例和接口单元测试都是能够提高代码质量的方式,各有优劣。本文从编程者的角度出发,更加注重的是代码覆盖测试,毕竟只有写代码的人才能更容易地把控代码中的业务逻辑,能够更好的编写单元测试用例以覆盖正常和异常的业务场景。

在做单元接口测试时,代码覆盖率常常是被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况。通常来说,我们会关注方法覆盖、语句覆盖、条件覆盖和分支覆盖这几种度量方式。

二、Spring Boot工程的代码单元测试

本文第一节主要都是讲了理论,相对比较枯燥。下面这一节将从实践的角度,来一步一步向大家展示如何在Spring Boot工程中对业务代码写单元测试用例。

1、版本环境

Spring Boot 1.4.1.RELEASE、JDK1.8

2、Spring Boot工程引入单元测试

在Spring Boot工程中引入单元测试比较简单,只需要简单地在pom文件中引入依赖如下:

在工程中引入spring-boot-starter-test后,就会有如下几个库:

(a)JUnit:Java语言的单元测试框架;

(b)SpringTest & Spring Boot Test:为Spring Boot程序提供集成测试的工具;

(c)AssertJ: 一种断言库;

(d)Hamcrest:也是一种断言库,不过更新频度较慢;

(e)Mockito :Java程序Mock测试的框架;

(f)JsonPath :Xpath在Json中的应用库;

(g)JSONassert:Json的断言库;

spring-boot-starter-test的pom依赖图如下:

3、工程中Service/Dao的单元测试

对于Spring Boot工程中的Service/Dao层的类来说,创建其单元测试方法比较简单,直接手动创建即可。

@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 {

        //测试用例数据准备

                   //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创建成功,jobId:{}",  respDto);

    }

         @After

         public void cleanUp() throws  Exception(){

                   //测试数据清理

                   //code here

         }

如上面的对Service层的单元测试用例代码可见,在带有@Before注解的方法setUp中完成对测试用例的数据准备,可以提前在测试环境数据库中插入测试用例所需依赖的测试局数据。在@Test注解的方法—create是单元测试真正执行的方法,示例中使用提前组织好的创建主机规格的Json数据作为参数调用被测试的Service层的VmService方法,执行创建主机的验证。同时使用断言机制,来判断返回结果是否跟预期的一致。其中,准备好的Json数据放在SpringBoot工程的src/test/resources下面。最后在,@After注解的方法cleanUp下执行提前插入数据的回滚和清理。

4、工程中Controller Api的单元测试

对Service/Dao层的类进行接口单元测试还是比较简便的。然而,一般的SpringBoot工程都需要对外部提供Api接口,因此有必要对Controller层进行单元测试以保证控制器执行的业务逻辑正确,这时候就得用到MockMvc了。使用MockMvc可以使得开发或者测试不必再借助postman这种Http调试工具进行手动测试,既提高测试的效率,也能够反复跑单元测试用例来进行回归验证。

Spring Test框架中的MockMvc实现了对Http请求的模拟,能够直接通过网络的形式,转换到Controller层的Api调用,这样在提高测试效率的同时可以不依赖外部环境。

@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";

         //此处为鉴权的Json测试数据

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

    @Autowired

    private WebApplicationContext context;

    private MockMvc mvc;

    @Before

    public void setUp() {

                   //测试用例数据准备

                   //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(){

                   //测试数据清理

                   //code here

         }

从上面对Controller层Api接口的单元测试示例代码可见,在带有@Before注解的setUp方法中,通过MockMvcBuilders工具类使用注入的WebApplicationContext上下文对象创建MockMvc对象。这里,MockMvc对象提供一组工具函数用来执行assert判断,都是针对web请求的判断。这组工具的使用方式是函数的链式调用,允许程序员将多个测试用例链接在一起,并进行多个判断。在带有@Test注解的generateOrderIdTest测试方法中,先加载提前准备好的鉴权请求JsonObject对象,然后MockMvc对象执行相应的post请求,其中参数为带有Header头的MockHttpServletRequestBuilder对象。最后,通过assertEquals断言机制来确认接口返回是否为Http响应的正确编码(200)。如同之前的一样,@After注解的方法cleanUp下执行提前插入数据的回滚和清理。

三、Spring Boot工程集成Cobetura插件

通过上面的内容,可以在Spring Boot工程中完成对Controller/Service/Dao层的添加单元测试用例,但仅限于此只能通过单元测试用例的结果(是否跑成功)来判断用例正确与否,而无法来判断测试的其他度量指标,比如本文前面提到的方法覆盖、语句覆盖、条件覆盖和分支覆盖等。因此,这节通过引入第三方组件—Cobertura来完成这一目标。

Cobertura 是一种开源的代码覆盖率检测工具,它通过检测基本的代码,并观察在测试包运行时执行了哪些代码和没有执行哪些代码,并最终以html或者xml的格式来呈现最终测试的度量指标结果(比如分支覆盖率和代码行覆盖率)。

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

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



2、运行Coberuta插件生成测试报告

在Spring Boot工程目录下执行以下maven命令—“mvn cobertura:cobertura”,执行完后会在target目录里找到site目录,用浏览器打开里面的index.html,这就是测试用例执行完后cobertura-maven-plugin得出的覆盖率报告。如图下所示:



四、Cobertura与自动化构建工具Jenkins的集成

仅在本地对Spring Boot工程执行Cobertura的maven命令,并不能很好的实现自动持续集成的目标。这一节主要将介绍如何在Jenkins工具中一步步集成Cobertura插件并完成Spring Boot工程的代码覆盖率测试报告输出。

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


2、配置jenkins工具,修改maven的执行命令,这里主要是添加cobertura执行命令clean cobertura:cobertura package。


3、在Add post build action这个配置项中选择如下Publish Cobertura Coverage Report:


4、这一步中需要选择一个配置项,该配置项目是最终cobertura生成xml/html report的路径,在示例中的路径为**/target/site/cobertura/coverage.xml。


5、最后,重新build该项目,即可在项目中看到本工程代码覆盖率的测试用例报告了:


五、总结

本文从代码质量与单元测试用例方面切入,先介绍了如何在Spring Boot工程中完成各层(Controller Api/Service/Dao层)的接口单元白盒测试,随后介绍了如何在Spring Boot工程中集成Cobertura插件,并利用Jenkins工具进行自动化持续集成以产生代码覆盖率的测试报告。限于笔者的才疏学浅,对本文内容可能还有理解不到位的地方,如有阐述不合理之处还望留言一起探讨。

个人专属的公众号(匠心独运的博客),欢迎关注一起交流和学习二维码如下:


匠心独运的博客
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • 在天桥,我与曾经的自己并肩走着; 夜很黑,但有微黄的夜灯打着前方的路; 我看着她,一身校服,两撮马尾,轻盈活泼; ...
    遇见you时阅读 260评论 0 1
  • 也是写给我自己的,不逼逼,直入正题。 最近在给家里的小工作坊招聘工人。强烈感觉到招聘真的需要成本,最基本的,在各个...
    我的天啊东西阅读 232评论 0 0
  • 性能测试是什么:性能测试就是通过特定的方式对被测试系统按照一定测试策略施加压力,获取该系统的响应时间、TPS、吞吐...
    花开沉浮阅读 4,311评论 0 4