zoukankan      html  css  js  c++  java
  • JUnit4 使用指南三 (Runner 特性分析)

    大家有没有想过这个问题:当你把测试代码提交给JUnit框架后,框架如何来运行你的代码呢?答案就是——Runner。在JUnit中有很多个Runner,他们负责调用你的测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。可能你会觉得奇怪,前面我们写了那么多测试,并没有明确指定一个Runner啊?这是因为JUnit中有一个默认Runner,即BlockJUnit4ClassRunner,如果你没有指定,那么系统自动使用默认Runner来运行你的代码。
    以第一章节的测试代码为例:
    package com.rigel.ut;

    import org.junit.Test;

    public class CalculatorTest {

    @Test
    public void testAdd() {
    // ...
    }
    }
    这段代码相当于:
    package com.rigel.ut;

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.internal.runners.BlockJUnit4ClassRunner;

    @RunWith(
    BlockJUnit4ClassRunner.class)
    public class CalculatorTest {

    @Test
    public void testAdd() {
    // ...
    }
    }

    一般情况下,默认测试运行器可以应对绝大多数的单元测试要求;当使用 JUnit 提供的一些高级特性(例如即将介绍的两个特性)或者针对特殊需求定制JUnit测试方式时,显式的声明测试运行器就必不可少了。在Junit4 中,Junit为我们定义好了一些运行器,他们的层次结构如下:
    其中ParentRunner是一个抽象类,包含了一个Runner的List,可以负责多个Runner运行。Suite是 一个测试套,继承了ParentRunner。BlockJUnit4ClassRunner则是Juint4默认的运行器,叫成Block是因为他是按 顺序一个一个执行测试用例的,Junit4中没有提供实现多线程执行的运行器。Junit4这个运行器只是单纯继承了 BlockJUnit4ClassRunner没有对其进行更改,并且它是final类型的,不允许继续被继承。Enclosed是实现内部类的测试类的运行器。Parameterized则可以设置参数化的执行测试用例。JUnit38ClassRunner是为了向后兼容JUnit3而定义的运行器。你也可以继承上面的类来实现新的运行器和注解功能。下面我们主要对Parameterized及Suite Runner进行介绍。
    1. Parameterized Runner 实现参数化测试
    为了保证单元测试的严谨性,我们模拟了不同的测试数据来测试方法的处理能力,为此我们编写了大量的单元测试方法。这些测试方法都是大同小异:代码结构都是相同的,不同的仅仅是测试数据和期望值,为了解决这个问题,JUnit4提供了参数化测试。
    举个简单的例子,比如我们需要对Calculator的加法功能进行测试,我们需要考虑“正数+正数”、“正数+负数”、“负数+负数”等等情况,因此我们可能需要像下面的代码那样写多个自己的测试方法:
    package com.rigel.ut;

    import org.junit.Assert;
    import org.junit.Test;


    public class AddTest {

    private Calculator calc = new Calculator();

    @Test
    public void testAdd1() {
    calc.add(
    1,4);
    int result = 5;
    Assert.assertEquals(result, calc.getResult());
    }

    @Test
    public void testAdd2() {
    calc.add(
    -1,-4);
    int result = -5;
    Assert.assertEquals(result, calc.getResult());
    }

    // any other test methods
    // ...

    }
    这些测试方法内容相同,仅仅只是测试数据有差异而已,写很多Test方法,其实是比较让人纠结的。而JUnit4提出的“参数化测试”,可以只写一个测试函数,把这若干种情况作为参数传递进去,一次性的完成测试。代码实现如下:
    package com.rigel.ut;

    import java.util.Arrays;
    import java.util.Collection;

    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;

    @RunWith(Parameterized.
    class)
    public class AddTest {

    private int result;
    private int param1;
    private int param2;


    /**
    * 存放需要进行测试的数据集合
    *
    */
    @Parameters
    @SuppressWarnings(
    "rawtypes")
    public static Collection prepareData() {
    Object[][] data
    = {{5, 1, 4}, {-3, 1, -4}, {-5, -1, -4}};

    return Arrays.asList(data);
    }

    /**
    * 对变量进行初始化
    *
    */
    public AddTest(int result, int param1, int param2) {
    this.result = result;
    this.param1 = param1;
    this.param2 = param2;
    }

    @Test
    public void addTest1() {
    Calculator calc
    = new Calculator();
    calc.add(param1, param2);
    Assert.assertEquals(result, calc.getResult());
    }

    }

    代码的实现过程大致如下。首先,因为是采用了参数化测试,这时候TestCase所采用的Runner已经不再是系统默认的Runner,所 以,在类的定义处,必须通过@RunWith注解指定该TestCase采用的是Parameterized.class Runner;其次,因为需要设定你的测试数据集合,主要是通过@parameters注解标注的 prepareData 方法来实现的,其返回的便是一个包含测试数据及测试结果的数据集合;最后需要定义该测试类的参数初始化过程,即需要制定其定义的参数是如何与设定的测试数 据集合中的数据对应上。在此基础上,便可以利用定义的参数来写你的测试方法,这样只需要定义一次@Test注解的测试方法,就可以把所有的测试数据都跑一 遍了。其最后测试结果如下:
    2. Suite Runner 实现打包测试
    一般在一个项目中,只写一个测试类是不可能的,我们会写出很多很多个测试类。如何这些测试类必须一个一个的执行,也是非常麻烦的事情。鉴于此,JUnit为我们提供了打包测试的功能,将所有需要运行的测试类集中起来,一次性的运行完毕,这大大的方便了我们的测试工作。
    为 了方便说明,我们分开在两个测试类 AddTest & SubstractTest中,分别测试Calculator的加法及减法功能,然后使用Suite Runner实现一次Run两个TestCase。其中AddTest源代码同上,而SubstractTest代码如下:
    package com.rigel.ut;

    import org.junit.Assert;
    import org.junit.Test;

    public class SubstractTest extends SupperTest{

    private Calculator calc = new Calculator();

    @Test
    public void testSubstract() {
    int result = 5;
    calc.substract(
    10, 5);
    Assert.assertEquals(result, calc.getResult());
    }

    }
    实现打包测试的TestCase取名“SuiteTest”,其代码实现如下:
    package com.rigel.ut;

    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;

    @RunWith(Suite.
    class)
    @Suite.SuiteClasses({AddTest.
    class, SubstractTest.class})
    public class SuiteTest {

    }

    从“SuiteTest.java”源代码可以看出,该测试类没有任何实现,其只是通过@RunWith注解标识测试采用的Runner为 Suite Runner,另外通过@Suite.SuiteClasses注解将所有需要进行测试的类打包进来。最后SuiteTest的测试结果如下:
    从图中可以很清晰的看到打包测试的具体情况。总结一下,本章节主要对JUnit4的Runner特性进行了简单的介绍,重点介绍了其中的参数化测试与打包测试的实现。本章节到此结束。谢谢。
    PS: 三篇文档并非原创,算是自己看了些文档然后进行的整合吧,只是希望能把JUnit4的一些常见用法讲清楚,希望对大家有所帮助
  • 相关阅读:
    第三章 p62 或运算
    p57 字符串的长度
    p53 ASCII码
    整数类型,如同时钟
    重要:原码、反码、补码...
    p42 实验溢出(上溢)
    P40 字节单位:KMGT
    p38 二、八、十六进制的对应关系
    p13 数组元素的地址
    p11 内存中的数据和地址
  • 原文地址:https://www.cnblogs.com/shine_cn/p/2060927.html
Copyright © 2011-2022 走看看