单元测试(二)测试框架:Junit

一、概述

JUnit是一个Java语言的单元测试框架。JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。
JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。
Junit促进了“先测试后编码”的理念,签掉建立测试数据的一段代码,可以先测试然后再应用,增加程序员产量和稳定性,可以减少程序员压力和花费在排错上的时间。
使用JUnit,需要在maven的pom文件中添加Junit的依赖(非maven项目导入Junitjar包):

<dependencies>
	[...]
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
	[...]
</dependencies>

或者springboot项目中(springcloud微服务项目)maven的pom文件中导入springboot的测试依赖综合依赖也可涵盖junit的依赖:

<dependencies>
	[...]
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<version>2.1.5.RELEASE</version>
		</dependency>
	[...]
</dependencies>

或者:

<dependencies>
	[...]
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-test</artifactId>
			<version>2.1.5.RELEASE</version>
		</dependency>
	[...]
</dependencies>

二、框架构成

Junit的测试类包含测试方法,测试方法带有断言,当需要一次运行多个测试类时就需要创建测试集(test suit或者Suite来打包多个测试类),Runner形成Junit框架的核心。

  • 测试类

包含一个或多个测试方法的类为测试类,测试方法即用@Test注解的方法,使用一个测试类可以把类的行为归为一组。
Junit在调用每个@Test方法前为测试类创建一个新的实例,提供测试方法之间的独立性。
测试类提供了在所有测试调用指令前发起的setUp方法,在所有测试方法运行完后的tearDown方法,便于测试各种复杂场景。

  • 测试集

把多个测试类归为一组方式为测试集。
如果没有为测试类定义一个测试集,那么junit默认会自动提供一个测试集包含测试类的所有测试。通常使用测试集将同一个包中测试类整合为一个测试集百年与运行。
在Junit中** @RunWith和@Suite **都被组合用作运行测试集。
测试集写法遵循原则:
1.创建一个空类作为测试集的入口
2.使用RunWith和SuiteClass来修饰这个空类
3.将Suite作为参数传给RunWith,@RunWith(Suite.class)
4.将需要集合到一起运行的测试类作为数组传递给SuiteClassess,@SuiteClassess({xxx1Test.class,xxx2Test.class…})

@RunWith(Suite.class)
@Suite.SuiteClasses(value={XXX1Test.class,XXX2Test.class...})
public class AllOrderTestSuite{
}
  • 测试运行器(Runner)

要运行一个基础的测试类,不需要特别配置Junit会为你使用默认测试运行器来管理你的测试类的生命周期,包括创建类、调用测试方法等。BlockJUnit4ClassRunner是在没指定其它Runner的情况下的默认Runner
但是默认的测试运行器每次只能运行一个测试方法,且在复杂业务时方法中的对象会互相依赖引用时默认的Junit运行器无法管理复杂的调用关系,因此Junit提供了各种测试运行器。使用@RunWith可以指定运行测试类的运行器,常见的运行器有如下几种:
1.JUnit4运行器:当前版本的JUnit中调用默认的JUnit 4运行器
2.Suite运行器:能同时运行多个测试类的所有测试方法的套件运行器
3.SpringJUnit4ClassRunner:测试运行于Spring环境,在测试类中可以使用Spring的依赖注入事务等Spring框架特有的功能
4.Parameterized:参数测试
5.MockitoJUnitRunner:自动地初始化mock,通常作为PowerMock测试类的运行器
相关参考:
Runner启动代码分析
各常用运行器及运行器使用区别

三、常用API


    @Test
    public void testAssertionsApi(){
        String str1 = new String("abc");
        String str2 = new String("abc");
        String str3 = null;
        String str4 = "abc";
        String str5 = "abc";
        int val1 = 5;
        int val2 = 6;
        String[] array1 = {"one","two","three"};
        String[] array2 = {"one","two","three"};
        String[] array3 = {"one","three","two"};

        //判断两个对象是否相同(使用对象的equal方法比较,A.equals(B))
        assertEquals(str1,str2);
        assertEquals(str1,str4);
        
        //判断两个对象是否为同一实例(A == B,引用指向同一对象)
        assertSame(str4,str5);
        assertNotSame(str1,str4);
        
        //判断是否为空
        assertNull(str3);
        assertNotNull(str1);
        
        //判断条件是否成立
        assertTrue(val1 < val2);
        assertFalse(val1 > val2);
        
        //判断数组是否相同(判断顺序为 ary1 == ary2 => 是否为空 =》 长度是否相等 =》 遍历同一下标的对象是否相等 ...ary[i].equal(ary2[i]))
        assertArrayEquals(array1,array2);
        //assertArrayEquals(array1,array3);失败
        
        //assertThat(T,March()),注意导包时使用org.hamcrest
        assertThat(val1,allOf(greaterThan(2),lessThan(8)));
        
        //fail()让测试失败
        // 一般用于测试不应达到的错误分支,正常测试用例不使用
    }
  • TestCase测试案例

    在进行单元测试的时候,在JUNIT4之前,我们需要测试的代码所在的类一般都需要直接或者间接继承自TestCase,TestCase继承自Assert类实现了Test接口,因此TestCase中可以直接使用Assert中的相关方法,使用Test接口的run执行案例。
    需要注意在我们这个类的测试流程,假设我们创建的TestCase子类中有两个测试用例testMethod1和testMethod2,对于我们类中的两个测试用例testMethod1和testMethod2,都会分别创建一个新的TestCase子类对象,并引起TestCase中的setUp和tearDown函数分别执行一遍,因此,在进行单元测试的过程中,我们可以在setUp当中进行一些初始化操作(如类的某些属性的赋值操作),在tearDown中进行一些扫尾工作(如类中某些对象所持有资源的释放)。
    TestCase类中常用重要方法如下:

    • countTestCases():被run执行的测试案例计数
    • createResult():创建默认的TestResult
    • getName():获取TestCase的名称
    • run()/run(TestResult result):运行测试案例并收集结果
    • setUp():测试案例执行前初始化
    • tearDown():测试案例执行完成后
    • toString():返回测试案例的一个字符串表示

tips:TestCase调用数序为:setUp->testXXX1->tearDown;setUp->testXXX2->tearDown;…

执行TestCase
1.使用JUnitCore.run来执行并分析结果:

public static void main(String[] args){
	Result  result = JUnitCore.run(xxxMyTest1.class);
	//输出测试结果
	for(Failure fail: result.getFailures()){
		Sytem.out.pringln(fail.toString());
	}
}

2.使用TestCase自带的run运行测试案例(每次必须指定测试方法名,否则会报找不到对应测试方法的错):

public class JunitApiTest extends TestCase {
	 public void testAssertionsApi(){
	 	....}
 public static void main(String[] args) {
        JunitApiTest test = new JunitApiTest();
        test.setName("testAssertionsApi");
        TestResult result = test.run();
        System.out.println(result.toString());
  }

3.idea中在测试类上直接执行测试用例(继承TestCase后类和testXXX方法变为可执行的测试案例)

JUNIT4中可以直接使用@Test注解更灵活方便的创建和执行单元测试测试案例,无需继承TestCase,Junit4虽然也支持TestCase这种写法,但是TestCase更适用与需要与JUnit 3(和/或Java 5之前的Java版本)兼容的情况,否则更建议使用使用JUNIT4的@Test写法,更容易使用各种开发工具执行和调试,也有了更多的拓展。
tips:新旧版本测试用例区别与使用请参考此博文

  • TestResult

TestResult类收集所有执行测试案例的结果。TestResult使用了java设计模式的Collecting Parameter模式,TestResult是收集很多运行的Test的运行结果,这里就需要对于这些运行结果进行管理,则TestResult类定义了如下相关的方法:

public synchronized void addError(Test test, Throwable t)    //新增一个错误到ArrayList<TestFailure>。

public synchronized void addFailure(Test test, AssertionFailedError t)  //新增一个失败到ArrayList<TestFailure>。
public synchronized void addListener(TestListener listener)   //在一个test中注册一个监听器到ArrayList<TestListener>,//这个监听器就是TestListener,实现类是TestRunner。

public synchronized void removeListener(TestListener listener)   //从一个test中取消这个监听器。

private synchronized List<TestListener> cloneListeners()   // 克隆一批监听器。

tips:TestResult详细方法分析参考此文

四、常用注解

  • @Test

将一个普通方法修饰成一个测试方法,
@Test(excepted=xx.class): xx.class表示异常类,表示测试的方法抛出此异常时,认为是正常的测试通过
@Test(timeout=毫秒数) :测试方法执行时间是否符合预期

  • @BeforeClass

会在所有的方法执行前被执行,static方法

  • @AfterClass

会在所有的方法执行之后进行执行,static方法

  • @Before

会在每一个测试方法被运行前执行一次

  • @After

会在每一个测试方法运行后被执行一次

  • Ignore

所修饰的测试方法会被测试运行器忽略

  • @RunWith

可以配置更改测试运行器org.junit.runner.Runner

  • @Parameters

用于使用参数化功能。

tips:注解执行顺序
beforeClass->before->testXXX1->after;before->testXXX2->after;…afterClass;

其他相关

junit版本升级到了5了,junit5比junit4做了更多模块化的框架,添加了更多的更丰富的注解。如有更复杂测试需求,自行学习。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章