自动化单元测试实践之路

发表于:2014-6-06 10:40

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:李乐    来源:51Testing软件测试网采编

  保证所有项目的目录结构在任何服务器上都是一样的,每个目录起什么作用都很清楚明了。
  3、统一软件构建阶段
  http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
  Maven2把软件开发的过程划分成了几个经典阶段,比如你先要生成一些java代码,再把这些代码复制到特定位置,然后编译代码,复制需要放到classpath下的资源,再进行单元测试,单元测试都通过了才能进行打包,发布。
  测试框架:JUnit&Mockito
  JUnit
  JUnit是一个Java语言的单元测试框架。
  2013年见过一个旧项目,测试代码还是以main作为入口,为什么要使用JUnit?
  JUnit 的优点是整个测试过程无人值守,开发无须在线参与和判断最终结果是否正确,可以很容易地一次性运行多个测试,使得开发更加关注测试逻辑的编写,而不是增加构建维护时间。
  团队示例代码:
// 功能代码
package com.chinacache.portal.service;
public class ReportService {
public boolean validateParams() {
}
public String sendReport(Long id) {
}
public String sendReport(Long id, Date time) {
}
}
// 单元测试代码
package com.chinacache.portal.service; // 必须与功能代码使用相同 package
public class ReportServiceUnitTest { // 测试类名以 UnitTest (单元测试) 或 InteTest (集成测试) 结尾
// 测试方法名以 test 开头,然后接对应的功能方法名称
@Test
public void testValidateParams() {
}
// 如果功能方法存在重载,则再接上参数类型
@Test
public void testSendReportLong() {
}
// 如果一个功能方法对应多个测试方法,不同测试方法可使用简洁而又有含义的单词结尾,例如 success、fail 等
@Test
public void testSendReportLongDateSuccess() {
}
// 这样通过测试方法名即可知道:测的是哪个功能方法,哪种情况
@Test
public void testSendReportLongDateFail() {
}
}
  Mockito
  Mockito是一个针对Java的mocking框架。使用它可以写出干净漂亮的测试用例和简单的API。它与EasyMock和jMock很相似,通过在执行后校验什么已经被调用,消除了对期望行为(expectations)的需要,改变其他mocking库以“记录-回放”(这会导致代码丑陋)的测试流程,使得自身的语法更像自然语言。
  Mockito示例:
List mock = mock(List.class);
when(mock.get(0)).thenReturn("one");
when(mock.get(1)).thenReturn("two");
someCodeThatInteractsWithMock();
verify(mock).clear();
EasyMock示例:
List mock = createNiceMock(List.class);
expect(mock.get(0)).andStubReturn("one");
expect(mock.get(1)).andStubReturn("two");
mock.clear();
replay(mock);
someCodeThatInteractsWithMock();
verify(mock);
  官方对比文章:http://code.google.com/p/mockito/wiki/MockitoVSEasyMock
  反馈平台:Jenkins&Sonar
  持续集成平台:Jenkins
  Jenkins 的前身是 Hudson 是一个可扩展的持续集成引擎,主要用于:
  持续、自动地构建测试软件项目
  监控一些定时执行的任务
  Jenkins将作为自动化单元测试持续集成的平台,实现自动化构建。
  
图-2-3-Jenkins平台
  代码质量管理平台:Sonar
  Sonar (SonarQube)是一个开源平台,用于管理源代码的质量。Sonar 不只是一个质量数据报告工具,更是代码质量管理平台。支持的语言包括:Java、PHP、C#、C、Cobol、PL/SQL、Flex 等。
  主要特点:
  代码覆盖:通过单元测试,将会显示哪行代码被选中
  改善编码规则
  搜寻编码规则:按照名字,插件,激活级别和类别进行查询
  项目搜寻:按照项目的名字进行查询
  对比数据:比较同一张表中的任何测量的趋势
  Sonar将作为自动化单元测试反馈报告统一展现平台,包括:
  单元测试覆盖率、成功率、代码注释、代码复杂度等度量数据的展现。
  
图-2-4 Sonar平台
  3 原则
  自动化测试金字塔,也称为自动化分层测试,Unit是整个金字塔的基石,最重要特点是运行速度非常快;第二个重要特点是UT应覆盖代码库的大部分,能够确定一旦UT通过后,应用程序就能正常工作。
  Unit:70%,大部分自动化实现,用于验证一个单独函数或独立功能模块的代码;
  Service:20%,涉及两个或两个以上,甚至更多模块之间交互的集成测试;
  UI:10%,覆盖三个或以上的功能模块,真实用户场景和数据的验收测试;
  这里仅仅列举了每个层次的百分比,实际要根据团队的方向来做调整。
  自动化单元测试原则
  提交代码、运行测试的重点是什么?快速捕获那些因修改向系统中引入的最常见错误,并通知开发人员,以便他们能快速修复他们。提交阶段提供反馈的价值在于,对它的投入可以让系统高效且更快地工作。
  隔离UI操作
  UI应当作为更高层次的测试Level,需要花费大量时间准备数据,业务逻辑复杂,过早进入UI阶段,容易分散开发的单元测试精力。
  隔离数据库以及文件读写网络开销等操作
  自动化测试中如果需要将结果写入数据库,然后再验证改结果是否被正确写入,这种验证方法简单、容易理解,但是它不是一个高效的方法。这个应当从集成测试的Level去解决。
  首先:与数据库的交互,是漫长的,甚至有可能要投入维护数据库的时间,那将成为快速测试的一个障碍,开发人员不能得到及时有效的反馈。假设,我需要花费一个小时,才能验证完毕与数据库交互的结果,这种等待是多么漫长呀。
  其次,数据管理需要成本,从数据的筛选(线上数据可能是T级)到测试环境的M级别,如何把筛选合适的大小,这都使得管理成本增加(当然在集成测试中可以使用DBUnit来解决部分问题)。
  最后,如果一定要有读写操作才能完成的测试,也要反思代码的可测试性做的如何?是否需要重构。
  单元测试决不要依赖于数据库以及文件系统、网络开销等一切外部依赖。
  使用Mock替身与Spring容器隔离
  如果在单元测试中,还需要启动Spring容器进行依赖注入、加载依赖的WebService等,这个过程是相当消耗时间的。
  可以使用模拟工具集:Mockito、EasyMock、JMock等来解决,研发团队主要是基于Mockito的实践。与需要组装所有的依赖和状态相比,使用模拟技术的测试运行起来通常是非常快,这样子开发人员在提交代码之后,可以在持续集成平台快速得到反馈。
  设计简单的测试
  明确定义方法:
  成功:public void testSendReportLongDateSuccess()
  失败:public void testSendReportLongDateFail(),可以包括异常
  和单一的断言,避免在一个方法内使用多个复杂断言,这会造成代码结构的复杂,使得测试的复杂性提高。
  定义测试套件的运行时间
  使用Mock构建的单元测试,每个方法的构建时间应该是毫秒级别,整个类是秒级别,理想的是整体构建时间控制在5分钟以内,如果超过怎么办呢?
  首先,拆分成多个套件,在多台机器上并行执行这些套件;
  其次,重构那些运行时间比较长且不经常失败的测试类;
  更多参考推荐阅读:《Unit Testing Guidelines》
  http://geosoft.no/development/unittesting.html
  4 流程
  
图-4-1-典型工作流程
  开发人员遵循每日构建原则,提交功能代码、测试代码(以UnitTest结尾的测试类)到Svn;
  Jenkins平台,根据配置原则(假设配置定时器每6分钟检查Svn有代码更新则构建)进行:代码更新、代码编译、UnitTest、持续反馈的流水线工作;
  构建结果发送到Sonar,并且把失败的构建以邮件方式通知影响代码的开发人员;
  开发人员、测试人员需要在Sonar平台进行review;
  5 实践
  Jenkins配置重点
  构建触发器:推荐使用PollSCM
  Poll SCM:定时检查源码变更(根据SCM软件的版本号),如果有更新就执行checkout。
  Build periodically:周期进行项目构建(它不care源码是否发生变化)。
  配置时间:H/6 * * * *
  Build配置
  Goals and options:emma:emma -Dtest=*UnitTest soanr:sonar
  注明:
  emma:emma,Add the "emma:emma" goal to your build to generate Emma reports;
  -Dtest=*UnitTest,参数配置,运行以UnitTest结尾的测试类;
  sonar:sonar,来触发静态代码分析。
  需要安装Emma Plugin(https://wiki.jenkins-ci.org/display/JENKINS/Emma+Plugin)
  构建后操作
  增加Aggregate downstream test results,勾选自动整合所有的downstream测试;
  增加Editable Email Notification,在“高级”选项增加触发器“Unstable”,
  勾选“Send To Committers”,Check this checkbox to send the email to anyone who checked in code for the last build。
  注明:Editable Email Notification插件是 https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin
  另外一些Jenkins的单元测试覆盖率展现方式,可以查看官网。
  构建管理工具(Maven)
  项目统一使用Maven进行构建管理,在pom.xml中进行依赖jar包配置
  持续集成服务器上同时需要安装Maven,setting.xml除了配置仓库之外,还需要配置sonar,包括sonar服务器地址、数据库连接方式:
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- EXAMPLE FOR MYSQL -->
<sonar.jdbc.url>
jdbc:mysql://127.0.0.1:3306/sonar?useUnicode=true&characterEncoding=utf8
</sonar.jdbc.url>
<sonar.jdbc.driverClassName>com.mysql.jdbc.Driver</sonar.jdbc.driverClassName>
<sonar.jdbc.username>sonar</sonar.jdbc.username>
<sonar.jdbc.password>sonar</sonar.jdbc.password>
<!-- SERVER ON A REMOTE HOST -->
<sonar.host.url>http:/127.0.0.1:9000</sonar.host.url>
</properties>
</profile>
43/4<1234>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号