JUnit4


JUnit4 介绍

JUnit 是 Java 编程语言的单元测试框架,用于编写和运行可重复的自动化测试。

JUnit 特点:

  • JUnit 是一个开放的资源框架,用于编写和运行测试。
  • 提供注解来识别测试方法。
  • 提供断言来测试预期结果。
  • JUnit 测试允许你编写代码更快,并能提高质量。
  • JUnit 优雅简洁,没那么复杂,花费时间较少。
  • JUnit 测试可以自动运行并且检查自身结果并提供即时反馈,所以也没有必要人工梳理测试结果的报告。
  • JUnit 测试可以被组织为测试套件,包含测试用例,甚至其他的测试套件。
  • JUnit 在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色。

JUnit4 改进:

  • JUnit4 是 JUnit 框架有史以来的最大改进,其主要目标便是利用 Java5 的 Annotation 特性简化测试用例的编写。

  • 什么是 Annotation:这个单词一般是翻译成元数据,元数据就是描述数据的数据。也就是说,这个东西在 Java 里面可以用来和 public、static 等关键字一样来修饰类名、方法名、变量名。修饰的作用是描述这个数据是做什么用的,正如 public 的作用是描述这个数据是公有的。


JUnit4 注解

注解 描述
@Test 将一个方法标记为测试方法,使其可以作为一条测试用例
@Before 每一个测试方法调用前必执行的方法
@After 每一个测试方法调用后必执行的方法
@BeforeClass 所有测试方法调用前执行一次,在测试类没有实例化之前就已被加载,需用 static 修饰
@AfterClass 所有测试方法调用后执行一次,在测试类没有实例化之前就已被加载,需用 static 修饰
@Ignore 每个被注解为 @Ignore 的方法将不再执行
@Runwith 放在测试类名上,用来确定这个类怎么运行的。也可以不标注,会使用默认运行器
@Parameters 用于使用参数化功能
@SuiteClasses 用于套件测试

详解:

@Test

  • @Test 注解的 public void 方法将会被当做测试用例。

  • JUnit 每次都会创建一个新的测试实例,然后调用 @Test 注解方法。

  • 任何异常的抛出都会认为测试失败

  • @Test 注解提供 2 个参数:

    1. expected:定义测试方法应该抛出的异常,如果测试方法没有抛出异常或者抛出了一个不同的异常,测试失败。
    2. timeout:如果测试运行时间长于该定义时间,测试失败(单位为毫秒)。

@After

  • 如果在 @Before 注解方法中分配了额外的资源,那么在测试执行完后,需要释放分配的资源。
  • 使用 @After 注解一个 public void 方法会使该方法在 @Test 注解方法执行后被执行
  • 即使在 @Before 注解方法、@Test 注解方法中抛出了异常,所有的 @After 注解方法依然会被执行。
  • 父类中的 @After 注解方法会在子类 @After 注解方法执行后被执行。

@AfterClass

  • 如果在 @BeforeClass 注解方法中分配了代价高昂的额外的资源,那么在测试类中的所有测试方法执行完后,需要释放分配的资源。
  • 使用 @AfterClass 注解一个 public static void 方法会使该方法在测试类中的所有测试方法执行完后被执行。
  • 即使在 @BeforeClass 注解方法中抛出了异常,所有的 @AfterClass 注解方法依然会被执行。
  • 父类中的 @AfterClass 注解方法会在子类 @AfterClass 注解方法执行后被执行。

@Before

  • 当编写测试方法时,经常会发现一些方法在执行前需要创建相同的对象。

  • 使用 @Before 注解一个 public void 方法会使该方法在 @Test 注解方法被执行前执行(那么就可以在该方法中创建相同的对象)。

  • 父类的 @Before 注解方法会在子类的 @Before 注解方法执行前执行。

@BeforeClass

  • 有些时候,一些测试需要共享代价高昂的步骤(如数据库登录),这会破坏测试独立性,通常是需要优化的。

  • 使用 @BeforeClass 注解一个 public static void 方法,并且该方法不带任何参数,会使该方法在所有测试方法被执行前执行一次,并且只执行一次。

  • 父类的 @BeforeClass 注解方法会在子类的 @BeforeClass 注解方法执行前执行。

@Ignore

  • 对包含测试类的类或 @Test 注解方法使用 @Ignore 注解将使被注解的类或方法不会被当做测试执行。

  • JUnit 执行结果中会报告被忽略的测试数。

示例:JUnit4 执行过程

public class JunitTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("in before class");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("in after class");
    }

    @Before
    public void before() {
        System.out.println("in before");
    }

    @After
    public void after() {
        System.out.println("in after");
    }

    @Test
    public void testCase1() {
        System.out.println("in test case 1");
    }

    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }

}

执行结果:

in before class
in before
in test case 1
in after
in before
in test case 2
in after
in after class

JUnit4 断言

断言 描述
void assertEquals([String message], expected value, actual value) 断言两个值内容是否相等(第一个参数是一个可选字符串消息)。值类型可能是 int、short、long、byte、char、Object
void assertTrue([String message], boolean condition) 断言一个条件为真
void assertFalse([String message], boolean condition) 断言一个条件为假
void assertNotNull([String message], Object object) 断言一个对象不为空(null)
void assertNull([String message], Object object) 断言一个对象为空(null)
void assertSame([String message], Object expected, Object actual) 断言两个对象是否引用相同的对象
void assertNotSame([String message], Object unexpected, Object actual) 断言两个对象不是引用同一个对象
void assertArrayEquals([String message], expectedArray, resultArray) 断言预期数组和结果数组相等,数组类型可能是 int、short、long、byte、char、Object

示例:

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

public class JavaBase {

    @Test
    public void testDemo () {
        String s1 = "123";
        String s2 = "123";
        String s3 = new String("123");

        int[] i1 = new int[]{1, 2, 3};
        int[] i2 = new int[]{1, 2, 3};
        int[] i3 = new int[]{2, 1, 3};

        Assert.assertEquals(s1, s2);  // true
        Assert.assertEquals(s2, s3);  // true

        Assert.assertSame(s1, s2);  // true
        Assert.assertSame(s1, s3);  // false

        Assert.assertArrayEquals(i1, i2);  // true
        Assert.assertSame(i2, i3);  // false
    }
    
}

异常测试

@Test(expected) 提供了一个追踪异常的选项,让我们可以测试代码是否抛出了想要得到的异常。

示例:

    @Test(expected=ArithmeticException.class)
    public void testCase() {
        System.out.println("in test case 3");
        int a = 0;
        int b = 1 / a;  // 由于得到了一个预期异常,所以测试通过
    }

@RunWith

首先要分清几个概念:测试方法、测试类、测试集、测试运行器。

  • 测试方法就是用 @Test 注解的一些函数。
  • 测试类是包含一个或多个测试方法的一个 .java 文件。
  • 测试集是一个 suite,可能包含多个测试类。
  • 测试运行器则决定了用什么方式偏好去运行这些测试集/类/方法。

而 @Runwith 就是放在测试类名之前,用来确定这个类怎么运行的。也可以不标注,会使用默认运行器。常见的运行器有:

  • @RunWith(Parameterized.class):参数化运行器,配合 @Parameters 使用 JUnit 的参数化功能。
  • @RunWith(Suite.class):测试集运行器,如传入单个测试集。
  • @SuiteClasses({ATest.class, BTest.class, CTest.class}):测试集运行器,如传入测试类数组。
  • @RunWith(JUnit4.class):junit4 的默认运行器。
  • @RunWith(JUnit38ClassRunner.class):用于兼容 junit3.8 的运行器。
  • 一些其它运行器具备更多功能。例如 @RunWith(SpringJUnit4ClassRunner.class) 集成了 spring 的一些功能。

参数化测试

Junit4 引入了一个新的功能参数化测试。参数化测试允许开发人员使用不同的值反复运行同一个测试。

创建参数化测试的步骤如下:

  1. 为准备使用参数化测试的测试类指定特殊的运行器:org.junit.runners.Parameterized。
  2. 为测试类声明几个变量,分别用于存放期望值和测试所用数据。
  3. 为测试类声明一个带有参数的公共构造函数,并在其中为步骤二中声明的几个变量赋值。
  4. 为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,且返回值为 java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对。
  5. 编写测试方法,使用定义的变量作为参数进行测试。

案例:

package com.basetest;

import org.junit.*;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

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

// 质数检查
class PrimeNumberChecker {

    public Boolean validate(final Integer parimeNumber) {
        for (int i = 2; i < (parimeNumber / 2); i++) {
            if (parimeNumber % i == 0) {
                return false;
            }
        }
        return true;
    }
}

// 质数检查 测试类
@RunWith(Parameterized.class)
public class PrimeNumberCheckerTest {

    /**
     * 步骤二:声明变量
     */
    private Integer inputNumber;
    private Boolean expectedResult;
    private PrimeNumberChecker primeNumberChecker;

    /**
     * 步骤三:为测试类声明一个带有参数的公共构造函数,为变量赋值(参数即对应参数化数据)
     */
    public PrimeNumberCheckerTest(Integer inputNumber,
                                  Boolean expectedResult) {
        this.inputNumber = inputNumber;
        this.expectedResult = expectedResult;
    }

    /**
     * 步骤四:为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,且返回值为
     * java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对
     *   1)该方法必须由Parameters注解修饰
     2)该方法必须为 public static 的
     3)该方法必须返回 Collection 类型
     4)该方法的名字不做要求
     5)该方法没有参数
     */
    @Parameterized.Parameters
    public static Collection primeNumbers() {
        return Arrays.asList(new Object[][]{
                {2, true},
                {6, false},
                {19, true},
                {22, false},
                {23, true}
        });
    }

    @Before
    public void initialize() {
        primeNumberChecker = new PrimeNumberChecker();
    }

    /**
     * 步骤五:编写测试方法,使用自定义变量进行测试
     */
    @Test
    public void testPrimeNumberChecker() {
        System.out.println("Parameterized Number is : " + inputNumber);
        Assert.assertEquals(expectedResult,
                primeNumberChecker.validate(inputNumber));
    }

}

执行结果:

Parameterized Number is : 2
Parameterized Number is : 6
Parameterized Number is : 19
Parameterized Number is : 22
Parameterized Number is : 23

套件测试

“套件测试”是指捆绑了几个单元测试用例并运行起来。在JUnit中,@RunWith 和 @Suite 这两个注解可配合用来运行套件测试。

示例:

  • 测试类 1:
import org.junit.Test;

public class JunitTest1 {

    @Test
    public void printMessage(){
        System.out.println("in JunitTest1");
    }
}
  • 测试类 2:
import org.junit.Test;

public class JunitTest2 {

    @Test
    public void printMessage(){
        System.out.println("in JunitTest2");
    }
}
  • 测试集:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({
        /**
         * 此处类的配置顺序会影响执行顺序
         */
        JunitTest1.class,
        JunitTest2.class
    })
public class JunitSuite {

}
  • 测试类执行结果:
in JunitTest1
in JunitTest2
posted @ 2021-10-18 18:12  Juno3550  阅读(260)  评论(0编辑  收藏  举报