前言

在软件开发流程中,单测是非常重要的一环,保证代码质量和效率。但是,实际开发过程中很少有同学会花时间去写单测。一方面,由于项目节奏等原因没时间去写单测代码,另一方面,单测框架太多,找到一个好用其效率高的单测工具也需要一定的成本。

然而,单测除了能验证本身代码的逻辑外,还能对一些特殊场景进行验证,保证代码的健壮性,不会因为日后的需求迭代,结构变更而导致或者新增风险。所以,单测的好处很明显,需要大家在单测和代码直接做一个平衡。

单测的概念

先看一个概念,什么是单元测试:

单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

所以,单元测试主要包括以下几点:

单测技术介绍

|通常单测分为三个部分

Runner:

Runner的目的是为了帮助我们做资源加载等事情,定制单元测试的模板,让我们能够专注于单测case本身的书写,Runner可以理解为单元测试的基础框架。

常用的Runner:junit4,TestNG,IntlTest(IntlTestBlockJUnit4ClassRunner),springTest & springbootTest & SpringContainer4Test(SpringJunit4ClassRunner)等

Mocks:

代理被测试对象,真正对被测试的代码进改造,屏蔽其他外部依赖,让我们的测试用例能够调到我们的测试代码而不是真正的代码。

常用的Mock工具:Mockito,此外还有JMockit、EasyMock、jMock、PowerMock等。

Mock常用的场景:

  1. 外部依赖的应用的调用,比如WebService等服务依赖。
  2. DAO层(访问MySQL、Oracle、Emcache等底层存储)的调用等。
  3. 系统间异步交互通知消息。
  4. methodA里面调用到的methodB。
  5. 一些应用里面自己的Class(abstract,final,static)、Interface、Annotation、Enum和Native等。
Assert:

对测试的结果进行断言判断。

常用的断言工具:AssertJ,JSONassert

单测技术选型

1、Runner选择

目前比较流行的测试框架主要有两种:Junit4和TestNG,对比如下:

junit测试主要特征(单元测试结束JunitVS)(1)

主要关注的差别点:

【1】参数化测试

参数化测试是指给单元测试传多种参数值,验证接口对多种不同参数的处理是否正确。

对于n个不同参数组合的测试,JUnit 4要写n个测试用例。每个测试用例完成的任务基本是相同的,只是受测方法的参数有所改变。TestNG的参数化测试只需要一个测试用例,然后把所需要的参数加到TestNG的xml配置文件中。这样的好处是参数与测试代码分离,非程序员也可以修改参数,同时修改无需重新编译测试代码。

JUnit4的使用限制比TestNG多,并且TestNG使用更加灵活。

Junit4 :

测试注解:@RunWith、@Parameter

问题:测试每一个方法都需要新建一个类,并且得按照下面Demo中的方式传参:写一个@Parameters方法返回List的参数,并通过构造函数的方式进行传参。

@RunWith(value = Parameterized.class) public class JunitTest6 { private int number; public JunitTest6(int number) { this.number = number; } @Parameters public static Collection<Object[]> data() { Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } }; return Arrays.asList(data); } @Test public void pushTest() { System.out.println("Parameterized Number is : " number); } }

TestNG

用XML文件或者注解的方式进行传参:

XML文件:(只支持基础数据类型)

public class TestNGTest6_1_0 { @Test @Parameters(value="number") public void parameterIntTest(int number) { System.out.println("Parameterized Number is : " number); } }

参数化测试(支持复杂数据类型)

@Test(dataprovider = "Data-Provider-Function") public void parameterIntTest(Class clzz, String[] number) { System.out.println("Parameterized Number is : " number[0]); System.out.println("Parameterized Number is : " number[1]); } //This function will provide the patameter data @DataProvider(name = "Data-Provider-Function") public Object[][] parameterIntTestProvider() { return new Object[][]{ {Vector.class, new String[]{"java.util.AbstractList", "java.util.AbstractCollection"}}, {String.class, new String[] {"1", "2"}}, {Integer.class, new String[] {"1", "2"}} }; }

【2】依赖测试

JUnit 4测试的依赖性非常强,测试用例间有严格的先后顺序。前一个测试不成功,后续所有的依赖测试都会失败。TestNG 利用@Test 的dependsOnMethods属性来应对测试依赖性问题。某方法依赖的方法失败,它将被跳过,而不是标记为失败。

TestNG在依赖测试场景上更加的灵活

@Test public void method1() { System.out.println("This is method 1"); } @Test(dependsOnMethods={"method1"}) public void method2() { System.out.println("This is method 2"); }

【3】其他差别

1. JUnit只能进行单元测试,TestNG可以进行单元测试,功能测试,端到端测试,集成测试等。

2. TestNG需要一个额外的xml配置文件,配置测试的class、method甚至package。

3. TestNG的运行方式更加灵活:命令行、ant和IDE,JUnit只能使用IDE。

4. TestNG的annotation更加丰富,比如@ExpectedExceptions、@DataProvider等。

5. 测试套件运行失败,JUnit 4会重新运行整个测试套件。TestNG运行失败时,会创建一个XML文件说明失败的

综上:Runner的选型,我们选用TestNG。

Mocks的选择

Mock是我们代码中使用最多的一种操作了,Mock工具的好坏直接影响了我们单测的效率。

junit测试主要特征(单元测试结束JunitVS)(2)

Mock工具有很多,常见的有JMockit、EasyMock、jMock、PowerMock等,几种Mock工具的原理大同小异

|Jmockit

中文网网址:http://jmockit.cn/

(推荐)jmockit Tutorial :https://zhuanlan.zhihu.com/p/24719968

Assert选择

assert工具在这里推荐使用AssertJ

选择AssertJ的原因:

举个例子:

判断一个字符串包不包括a跟b两个字符。要这么写

//junit或testng assertTrue(stringbuffer.contains("a") && stringbuffer.contains("b")) //AssertJ assertThat(stringbuffer).contains("a").contains("b").as("判断字符串是否包括a|b")

相比之下,显然后者更加容易理解,而且as的注释更是让断言清晰。

  1. api库更强大。除了以上基础类型和异常、日期、类属性、soft断言api,更突出的优势是扩展了对以下领域的支持:DB(据说适配myBatis, Hibernate, JOOQ等多种DB框架)、Guava、Swing;Uri、xml、file;jdb8如:Future,Stream, Optional, Java 8 Date等
  2. api可读性更好,更加贴近自然语义,AssertJ中封装了海量的api,基本都可以从名字中明确理解含义

具体可看AssertJ官网地址:http://joel-costigliola.github.io/assertj/

,