JUnit4 测试示例

1. JUnit4 测试示例

// Calculator.java
public class Calculator{
    public int add(int a, int b){
        return a + b;
    }

    public int minus(int a, int b){
        return a - b;
    }

    public int square(int a, int b){
        return a * b;
    }

    // Bug: 死循环
    public void squareRoot(int a){
        for(; ;)
            ;
    }

    public int multiply(int a, int b){
        return a * b;
    }

    public int divide(int a, int b) throws Exception{
        if(0 == b){
            throw new ArithmeticException("除数不能为零!");
        }
        return a/b;
    }
}


// 单元测试类
public class CalculatorTest{
    private Calculator cal = new Calculator();

    @BeforeClass
    public static void before(){
        System.out.println("类加载之前....");
    }

    @AfterClass
    public static void after(){
        System.out.println("类被销毁之前...");
    }

    // @BeforeClass和@AfterClass都需要被 static 修饰

    @Before
    public void setUp() throws Exception{
        System.out.println("测试方法开始之前...");
    }

    @After
    public void tearDown() throws Exception{
        System.out.println("测试方法结束!");
    }

    @Test
    @Ignore // 忽略测试
    public void testAdd(){
        int result = cal.add(1, 3);
        System.out.println("测试加法++++");
        Assert.assertEquals(4, result);
    }

    @Test
    public void testMinus(){
        int result = cal.minus(5, 2);
        System.out.println("测试减法----");
        Assert.assertEquals(3, result);
    }

    @Test
    public void testMultiply(){
        int result = cal.multiply(4, 2);
        System.out.println("测试乘法****");
        Assert.assertEquals(8, result);
    }

    // 超时测试, 单位毫秒
   // 若测试运行超过 1000毫秒时,测试失败
    @Test(timeout = 1000)
    public void testSquareRoot(){
        System.out.println("测试平方根");
        cal.squareRoot(4);
    }

    // 异常测试
    @Test(expected = ArithmeticException.class)
    public void testDivide() throws Exception{
        System.out.println("测试除法...");
        cal.divide(4, 0);
    }
}

1.1 参数测试

  • 需求:如果SquareRoot()方法,需要使用不同的参数,测试多次,需要提供多个@Test方法;
  • JUnit4创建不同参数测试只需要五个步骤:

创建一个不含参数的通用测试;
创建一个返回Collection类型的static feeder 方法, 并用@Parameters注释加以修饰;
为在步骤1中定义的通用方法所要求的参数类型创建类成员;
创建一个持有这些参数类型的构造函数,并把这些参数类型和步骤3中定义的类成员相应地联系起来;
通过@RunWith注释,指定测试用例和Parameterized类一起运行;

// 测试用例
@RunWith(Parameterized.class)
public class CalculatorTest2{

    private Calculator cal = new Calculator();
    private int param;
    private int result;

    // 构造函数,对变量进行初始化
    public CalculatorTest2(int param, int result){
        this.param = param;
        this.result = result;
    }

    @Parameters
    public static Collection data(){
        return Arrays.asList(new Object[][]{
            {2, 4},
            {0, 0},
            {-3, 9},
        });
    }

    // 不含参数的通用测试
    @Test
    public void squareTest(){
        int temp = cal.square(param);
        Assert.assertEquals(result, temp);
    }
}

2. Runner 介绍

  • Runner是一个抽象类,负责运行测试和向RunNotifier通知(包括程序的启动,结束,失败);
  • 可以使用@RunWith来指定具体的Runner;
// org.junit.runner.Runner.java
public abstract class Runner implements Describable{

    public abstract Description getDescription();

    public abstract void run(RunNotifier notifier);

    // 统计需要测试方法的个数
    public int testCount(){
        return getDescription().testCount();
    }
}

2.1 Runner继承结构

  • public abstract class ParentRunner<T> extends Runner implements Filterable, Sortable

2.2 Runner 示例

2.2.1 BlockJUnit4ClassRunner

  • 测试类不使用@RunWith注解时,JUnit默认使用该Runner;

2.2.2 Suite

@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorTest.class, CalculatorTest2.class})
public class AllCalculatorTests{

}

// 上述代码,表名该类是一个打包测试类,包含了CalculatorTest.class和CalculatorTest2.class
// 里面所有的测试函数

2.2.3 Parameterized

  • 用于测试同一个函数,拥有不同参数的情况(示例见上)

2.2.4 Categories

@Category(Basic.class)
@Test
public void testMinus(){
    int result = cal.minus(5, 2);
    System.out.println("测试减法----");
    Assert.assertEquals(3, result);
}

@Category(Advanced.class)
@Test
public void testMultiply(){
    int result = cal.multiply(4, 2);
    System.out.println("测试乘法****");
    Assert.assertEquals(8, result);
}

// 定义用于分类的接口
public interface Basic(){

}

public interface Advanced(){

}

// 编写测试类
@RunWith(Categories.class)
@SuiteClasses(CalculatorTest.class)
@IncludeCategory(Basic.class)
public class CategoryTest{

}

// 输出:
类加载之前....
测试方法开始之前...
测试减法----
测试方法结束!
类被销毁之前...

2.2.5 Theories

  • Parameterized的改良版;
  • 将所有可能的结果都进行测试;
@RunWith(Theories.class)
public class TheoriesTest{

    @DataPoints
    public static String[] names = {"Tony", "Jim"};
    // 等同于:
    // @DataPoint
    // public static String nameT = "Tony";
    // @DataPoint
    // public static String nameJ = "Jim";

    @DataPoints
    public static int[] values = {10, 20};

    @Theory
    public void testMethod(String name, int age){
        System.out.println(String.format("%s's age is %s.", name, age));
    }
}


参考资料:

原文地址:https://www.cnblogs.com/linkworld/p/9054363.html