正文
四、造数技术
4.1 内存中造数
我们在运行单元测试的时候,为了满足调用参数的要求,不得不为参数对象设置值。比如,当参数对象为一个Person类的时候,倘若它的属性值不多,我们可以像上面的例子中一样,使用手动造数;但是,如果属性值很多,甚至中间还嵌套了其它对象怎么办?手动造数太繁琐了。
- java-faker,可以对生活中常用的事物进行造数,使用简单,但无法满足复杂对象的造数;
- easy-random,可以对复杂对象进行造数,而且可以自定义造数的值类型和范围;
- jmockdata,可以对复杂对象进行造数,而且可以自定义造数的值类型和范围;
这些工具库的使用都非常简单,参考文末列出的官方文档看下即可。
4.2 数据库造数
我们在测试DAO层关于SQL的增删查改前,要先提供一批专供测试使用的假数据,一般有以下方式:
使用内存数据库
如果不希望测试用例的执行污染测试数据库,那么可以建立一个专为测试用例执行使用的内存数据库,缺点是,需要维护所有的建表语句。
使用数据库造数工具
可以使用DBFactory之类的造数工具,往测试数据库中提前准备数据,但是测试完成后删除数据是个问题。
测试用例使用事务回滚
好处是不会对测试数据库造成数据污染,但是需要在测试用例逻辑执行前,手动准备数据;
五、Maven集成
我们在如上的学习过程中,都是写完单元测试后直接运行了。倘若我们在提交代码前,要运行所有的单元测试该怎么操作呢?总不可能一个个地打开所有地测试类,都点击运行一遍吧。
这里介绍使用Maven的插件进行单元测试运行的集成操作。
5.1 默认配置
首先,在pom文件中引入maven-surefire-plugin,版本选择最新版:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> </plugin>
其实,这就可以了,我们使用了默认配置,执行mvn生命周期的test,就可以运行src/test/java目录下的所有单元测试和集成测试了。
5.2 跳过执行测试用例
有时候我们编译工程并不像运行测试用例,那么可以增加如下配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <!--跳过执行测试用例--> <skipTests>true</skipTests> </configuration> </plugin>
5.3 选定运行测试用例
有些场景下,我们只想运行某一个/一类/一路径的测试用例,我们可以使用<include>来配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <!--只运行包含的测试--> <includes> <include>unit/**/*.java</include> </includes> </configuration> </plugin>
如上配置表示,只运行src/test/java/unit路径下所有java结尾的测试类中的测试用例;
5.4 排除运行测试用例
有时候,我们需要排除运行一些测试用例。比如,在编译阶段,我们只想快速地运行单元测试,而不要运行集成测试,那么就可以将集成测试所在的文件路径做如下的配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <!--需要排除的测试--> <excludes> <!--当不需要运行集成测试时添加如下文件内容--> <exclude>integration/**/*.java</exclude> </excludes> <!--设置并发执行测试,节约时间--> <parallel>methods</parallel> <threadCount>10</threadCount> </configuration> </plugin>
前提是,我们所有的集成测试类都必须放在src/test/java/integration目录下。
5.5 多线程运行测试用例
有时候,项目中的单元测试和集成测试非常多,一次执行会耗时比较久,那么可以设置多线程来执行:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <!--设置并发执行测试,节约时间--> <parallel>methods</parallel> <threadCount>10</threadCount> </configuration>
需要注意的时,要确保各测试用例之间没有调用依赖,否则便不可使用多线程的方式。
5.6 测试报告及覆盖率的查看
如果仅靠上面引入的maven-surefire-plugin插件,那么你只能在控制台看到运行的测试报告,如果要跟别人分享,十分不方便。可以通过引入maven-surefire-report-plugin插件:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-report-plugin</artifactId> <version>2.12.2</version> <configuration> <!--报告中是否显示成功率为100%的项目--> <showSuccess>false</showSuccess> </configuration> </plugin>
执行其中的surefire-report:report命令,就可以重新运行所有测试用例,并在target/site目录下生成一个html测试报告。
如果想查看测试覆盖率,那么就需要引入另外一个插件cobertura-maven-plugin:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>cobertura-maven-plugin</artifactId> <version>2.5.1</version> </plugin>
执行其中的cobertura:cobertura命令,就可以重新运行所有测试用例,并在target/site/cobertura目录下生成一个静态站点文件,找到其中的index.html,打开就可以看到各个测试覆盖率数据了。
5.7 其它配置
关于maven-surefire-plugin插件还有很多其它配置内容,可以参考文末引用自行阅读尝试。
六、经验总结
测试用例的名称一定要突显被测试代码的意图,名称不一定要以“Test”结尾,可以很长,单词之间用下划线连接;
要注重测试用例代码的可读性,让人一眼就能看出测试意图;
测试用例中应该避免使用分支和循环,可以拆成多个测试用例;
每个测试用例使用prepare-action-verify三段式结构;
不要在测试用例中捕获异常,应该抛出异常或者期待异常@Test(expected=SomeException),当然还可以使用ExpectedException;
测试用例不能依赖数据库中的已有数据,应该在测试用例中自己准备数据;
测试完成后应该回滚数据,避免造成数据库污染,保证测试用例可以反复执行;
通常不使用单元测试来测JavaBean和Controller,所以这两者中尽量也不要有业务逻辑;
七、参考文献
- AssertJ Corehttps://links.jianshu.com/go?to=https%3A%2F%2Fassertj.github.io%2Fdoc%2F
- AssertJ-DBhttps://links.jianshu.com/go?to=http%3A%2F%2Fjoel-costigliola.github.io%2Fassertj%2Fassertj-db.html
- JMockit中文网https://links.jianshu.com/go?to=http%3A%2F%2Fjmockit.cn%2Findex.htm
- java-fakerhttps://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2FDiUS%2Fjava-faker
- easy-randomhttps://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fj-easy%2Feasy-random%2Fwiki
- jmockdatahttps://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fjsonzou%2Fjmockdata
- 学习Maven之Maven Surefire Plugin(JUnit篇)https://links.jianshu.com/go?to=https%3A%2F%2Fwww.cnblogs.com%2Fqyf404%2Fp%2F5013694.html
- maven-surefire-pluginhttps://links.jianshu.com/go?to=http%3A%2F%2Fmaven.apache.org%2Fsurefire%2Fmaven-surefire-plugin%2Fusage.html