持续集成实践小结[2] —单元测试

前文提到,在UI自动化之外,我们着力探索了如何实施单元测试(unit test

  相对于UI自动化,单元测试方面的实践还是不够充分的,因此,这里也只是小结一下我们的经验

  概述

  首先明确一下,此处单元测试概念与经典意义有所不同,泛指所有:

  由开发工程师编写的,可以在开发本地一键运行的,运行时间在分钟级别的测试用例,用例执行会依赖不多的,但往往也是稳定可靠的外部环境

  测试框架一般使用TestNg而不是JUnit,主要原因在于TestNg的 DataProvider 功能很给力,非常适合用例须要覆盖多分支的场景

  用例组织原则:

  一个测试类对应一个功能类: funcOneTest.java 对应于 funcOne.java

  若干个测试方法对应一个功能方法:test_funcOne_smoke() & test_funcOne_normal() & test_funcOne_error() 对应于 funcOne()

  用例分类约定

  还是以 超市购物 为背景,写几个Demo用例

  Δ冒烟型用例 – 甲


@Test(description = "getNewestItems_冒烟_获取最新商品并检查若干关键属性")

public void test_getNewestItems_smoke() {

List<ItemVo> itemList = itemBean.getNewestItems(1);

Assert.assertTrue(itemList.size() == 16,        "size应该是16");

for (ItemVo vo : itemList) {

Assert.assertTrue(vo.getName() != null,     "name不能为空");

Assert.assertTrue(vo.getPrice() != null,    "price不能为空");

}

}

  说明:

  顾名思义,就是在用例中简单调用一下被测方法(method),主要是为了跑通流程,拒绝Block级别问题

  实践中,推荐 伴随着功能开发,随时编写冒烟用例,功能代码与冒烟用例一起提交代码库

  对于一些复杂的功能,功能开发的过程也是一个持续重构的过程,编码前期完成的冒烟用例,可以有效起到安全网作用

  Δ冒烟型用例 – 乙


@Test(description = "enter_and_leave_market_冒烟_进入与离开超市")

public void test_enter_and_leave_market_smoke() {

Custom tom = new Custom("Tom");

tom.enterMarket();

Assert.assertTrue(Custom.isAtMarket(tom),   "tom应该在超市内");

tom.leaveMarket();

Assert.assertFalse(Custom.isAtMarket(tom),  "tom应该不在超市");

}

  说明:

  这个用例把进入超市及离开超市这两个(强相关的)接口串起来了,目的在于走通流程

  实践中,建议 将新模块(函数)与其强相关的模块(函数)尽早进行简单的集成测试以提前发现一些问题

 Δ正常流程用例


@Test(description = "addToCart_正常流程_往购物车内添加各种类型数目的商品", dataProvider = "test_addToCart_normal_data")

@Rollback

public void test_addToCart_normal(String caseNote, long itemId, int count) {

Custom tom = new Custom("Tom");

this.setCustom(tom);

cartBean.addToCart(itemId, count);

Item item = tom.getCart.getItems.get(0);    // 获取购物车中的第一项商品

Assert.assertEquals(item.getId,      itemId,  "itemId is wrong");

Assert.assertEquals(item.getCount,   count,   "count is wrong");

}

@DataProvider

public Object[][] test_addToCart_normal_data() {

return new Object[][] {

// caseNote,                    itemId,     count

{"Milk  - just a dozen",        39001L,     12,  },

{"Bread - huge number",         116001L,    999},

{"Bean  - less then 10",        1018100L,   2},

};

}

  说明:

  这个示例代码演示了如何测试addToCart()的功能,假定这个方法内部有十分复杂的业务逻辑,我们须要覆盖各种场景

  可以看到,正常流程用例与冒烟用例其实差不多,不同的是,正常流程用例会覆盖更多分支,冒烟用例则一般是走通流程就行

  这个用例使用了@Rollback标签,用例执行后会回滚数据,而不会真正往数据库内插入数据;这个功能十分有用,可以大大减少数据准备与清理的工作;至于@Rollback背后的实现原理,此处暂时按下不表

  测试参数使用TestNg的@DataProvider组织起来,每一行都是一组测试数据,覆盖一种测试分支

  测试参数的第一列建议设置为caseNote,简单阐述用例的意图,可以有效提升用例可读性

  Δ异常流程用例


@Test(description = "addToCart_异常流程_往购物车内添加参数非法的商品", dataProvider = "test_addToCart_error_data")

@Rollback

public void test_addToCart_error(String caseNote, long itemId, int count, int expectedErrorCode) {

Custom tom = new Custom("Tom");

this.setCustom(tom);

try {

cartBean.addToCart(itemId, count);

Assert.fail();

} catch (Exception e) {

Assert.assertEquals(e.getErrorCode, expectedErrorCode);

}

}

@DataProvider

public Object[][] test_addToCart_error_data() {

return new Object[][] {

// caseNote,                        itemId,     count,  expectedErrorCode

{"iPad       - 0 count",            39001L,     0,      Cart.ZERO_COUNT},

{"MacBookPro - more then stock",    116001L,    1024,   Cart.MORE_THAN_STOCK},

{"no such item",                    0L,         1L,     Cart.NO_SUCH_ITEM}

};

}

  说明:

  如果不同的异常输入会有相应的 errorCode 的话, 可以把errorCode当成测试数据的一项参数传进去

 Δ特殊场景 & 复杂流程

  个别特殊场景,不方便使用@DataProvider合并的复杂流程,可以单独创建一个用例进行测试,函数命名的时候注明一下,例如:

  test_addToCart_error_withoutEnoughMoney() – 钞票不够

  test_addToCart_normal_mergeMultiCarts() – 合并多个购物车

  Δ前事不忘,后事之师

  出过Bug的地方(及其周边)补充单元测试覆盖,由单元测试帮你记住前事 – test_funcOne_issue12345_bugfix()

  用例编写流程

  用例编写顺序:

  开发新功能时,同步编写冒烟测试,用于自测及调试,功能代码与冒烟用例一起提交 – test_funcOne_smoke()

  稍晚,补充更多分支覆盖的正常流程用例,相当于进行又一轮自测 – test_funcOne_normal()

  最后,补充异常流程和特殊(复杂)场景用例 – test_funcOne_error() & test_funcOne_specialScenario()

  之所以这样安排,一个很重要的原因是希望 保持主干及正常流程的畅通,确保开发及测试不会Block

  此外:

  尽量把单个开发任务切分成多个小功能点,频繁提交,稳扎稳打,配合Jenkins & Sonar,多跑单元测试和静态代码检查,问题早发现早处理

  前事不忘,后事之师,出过Bug的地方补充单元测试

  补遗

  单元测试与静态代码检查(static analysis, SA)是一对好基友,两者可以统一显示在Sonar上面,在实践中往往一起考察

  关于Sonar,实乃居家必备,代码度量之利器,以后会另外讲述,这里先贴个图:

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-10-04 16:02:36

持续集成实践小结[2] —单元测试的相关文章

持续集成实践小结[1] —UI自动化

背景介绍 按照组织上的安排,咱游击到了S产品(一个快速成长中的Web产品)开搞持续集成. 考虑到S产品核心业务单一明确,前端功能简单,业务逻辑主要在后端的特点,制定了持续集成的实施策略: UI自动化为辅,用例少一点,精一点,降低维护成本,用例设计以冒烟和页面跳转,走通业务流程为主,目的是保障一个高可测性的测试环境: 单元测试重点跟进,自顶向下逐步覆盖各层接口,多覆盖各种分支路径,与UI自动化形成互补. 这里有个小插曲,我和S产品的测试负责人关于UI自动化用例的粒度和覆盖度有一些歧义,测试负责人坚

Jenkins与Docker的持续集成实践

本文讲的是Jenkins与Docker的持续集成实践[编者的话]持续集成(CI/CD)是一种软件开发实践.用于帮助团队成员频繁.快速的集成,测试他们的工作成果,以尽快发现集成错误. 更频繁.更早的集成意味着更早的发现问题.通过持续集成,及时发现和解决代码故障,提高代码质量,减少故障处理成本等等. [3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站]本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览:持续集成系统介绍:客户端与服务端的

Android项目持续集成实践之Gitlab CI(Docker版本)

接上一篇 Android项目持续集成实践之Gitlab CI. 在我看来,.gitlab-ci.yml 配置还是有些复杂,写的脚本还是有点多,有没有办法更精简一点呢? 有,那就是Android环境Docker化.(注:对Docker感兴趣的同学,请参考这本书<Docker -- 从入门到实践>). 我在这本书的指导下封装了一个包含Android开发环境的Docker镜像. 1. https://github.com/snowdream/docker-android 1. https://hub

IOS6.1单元测试持续集成实践

最近项目测试需要,调研并实践了下IOS下单元测试工具和框架.目前比较流行的工具有xcode自带的OCUnit.GHUnit等,我选择的是GHUnit,因为相比OCUnit,GHUnit具有如下优势: 1.开源框架 2.支持重复测试.单一测试.集成测试. 3.断言方法丰富 4.支持持续集成 5.测试类型多样(UI和Command Line) 官方地址如下:http://gabriel.github.io/gh-unit/ GitHub下载地址:https://github.com/gabriel/

Android项目持续集成实践之Gitlab CI

简介 持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成.每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误. 入门 下面我们来简单介绍,如果通过Gitlab CI来对Android项目持续集成. 一言不合,先甩给你一个项目链接:https://gitlab.com/snowdream/Citest 项目很简单,就是一个默认创建的Andro

云计算基础设施持续集成实践

[演讲PDF]: https://yq.aliyun.com/attachment/download/?id=1837 [演讲视频]: https://yq.aliyun.com/edu/lesson/551 研发和传统基础设施交互方式 通常情况下,在开发过程中需要和基础设施打交道,需要在项目中申请开发.测试以及预发生产环境.在IDC时代,我们需要向IT部门申请这些资源,其批准后,我们才能获得这些资源.如果这些资源恰巧不足,我们只能等待购买新的资源或者更换其他资源. 当拿到这些资源之后,需要对开

Jenkins 持续集成实践(以网易蜂巢为例)-1 Master 节点的创建

使用场景 当 Github 发生 push 操作时,能够触发测试环境的持续集成. 步骤 搭建 master 节点 蜂巢在官方 jenkins 镜像的基础上 预先安装了 jenkins 的插件 预置了用户 (jenkins/jenkins) jenkins节点分为 master 节点 slave 节点 Master/Slave 相当于 Server/Agent 的概念 Master 节点提供 web 接口来让用户管理 job 和 slave job 可以运行在 master 本机也可以被分配到 s

项目管理大法归档 - 思维导图、原型工具、接口测试、设计模式、版本管理、单元测试、持续集成、代码审查、Bug 跟踪

项目管理大法归档 - 思维导图.原型工具.接口测试.设计模式.版本管理.单元测试.持续集成.代码审查.Bug 跟踪 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 项目管理大法归档: 1.思维导

Flex 持续集成(CI)实践(Hudson)

项目开始后,持续集成会是一个关键的环节,本文针对Flex的开发的持续集成进行了一个实战,这些相关的工具和功能还是很强大的,通过组合这些工具,可以构建一个编译.单元测试.集成测试.代码检查等系列工作的CI服务,为后续的项目持续发展打下一定的基础. 运行Hudson http://hudson-ci.org 上下载文件 执行: java - ja r hudson.war 或 java -jar hudson.war --httpPort=8888 浏览器输入http://localhost:808