JUnit

JUnit是一个开源的Java语言的单元测试框架,专门针对Java设计,使用最广泛。JUnit是事实上的单元测试的标准框架。
当我们已经编写了一个Factorial.java文件后,我们想对其进行测试,需要编写一个对应的FactorialTest.java文件,以Test为后缀是一个惯例,并分别将其放入srctest目录中。最后,再添加相应的库。
单元测试中常使用断言方法:

  • assertEquals(expected, actual):期待两者相等
  • assertTrue(): 期待结果为true
  • assertFalse(): 期待结果为false
  • assertNotNull(): 期待结果为非null
  • assertArrayEquals(): 期待结果为数组并与期望数组每个元素的值均相等

    使用Fixture

    在测试的时候,我们经常遇到一个对象需要初始化,测试完可能还需要清理的情况。如果每个@Test方法都写一遍这样的重复代码,显然比较麻烦。
    JUnit提供了编写测试前准备、测试后清理的固定代码,我们称之为Fixture。 ``` public class CalculatorTest {

    Calculator calculator;

    @BeforeEach public void setUp() {

    1. this.calculator = new Calculator();

    }

    @AfterEach public void tearDown() {

      this.calculator = null;
    

    }

    @Test void testAdd() {

      assertEquals(100, this.calculator.add(100));
    

    } @Test void testSub() {

      assertEquals(-100, this.calculator.sub(100));
    

    } }

还有一些资源初始化和清理可能更加繁琐,而且会耗费较长的时间,例如初始化数据库。JUnit还提供了`@BeforeAll`和`@AfterAll`,它们在运行所有@Test前后运行,并且只运行一次,它们只能初始化静态变量。
## 异常测试
在Java程序中,异常处理是非常重要的。<br />我们自己编写的方法,也经常抛出各种异常。对于可能抛出的异常进行测试,本身就是测试的重要环节。<br />因此,在编写JUnit测试的时候,除了正常的输入输出,我们还要特别针对可能导致异常的情况进行测试。<br />我们仍然用`Factorial`举例:

public class Factorial { public static long fact(long n) { if (n < 0) { throw new IllegalArgumentException(); } long r = 1; for (long i = 1; i <= n; i++) { r = r * i; } return r; } }

在方法入口,我们增加了对参数`n`的检查,如果为负数,则直接抛出`IllegalArgumentException`。<br />现在,我们希望对异常进行测试。在JUnit测试中,我们可以编写一个`@Test`方法专门测试异常:

@Test void testNegative() { assertThrows(IllegalArgumentException.class, new Executable() { @Override public void execute() throws Throwable { Factorial.fact(-1); } }); }

JUnit提供`assertThrows()`来期望捕获一个指定的异常。第二个参数`Executable`封装了我们要执行的会产生异常的代码。当我们执行`Factorial.fact(-1)`时,必定抛出`IllegalArgumentException`。`assertThrows()`在捕获到指定异常时表示通过测试,未捕获到异常,或者捕获到的异常类型不对,均表示测试失败。<br />有些童鞋会觉得编写一个`Executable`的匿名类太繁琐了。实际上,Java 8开始引入了函数式编程,所有单方法接口都可以简写如下:

@Test void testNegative() { assertThrows(IllegalArgumentException.class, () -> { Factorial.fact(-1); }); }

## 条件测试
在某些情况下,需要排除一些@Test方法。这时尽量不要注释掉@Test,而是要加一个@Disabled。因为当注释掉@Test时,JUnit就不知道这时测试方法,而加上@Disabled,Junit知道这是个测试方法,只是暂时不运行,它会在测试结果中显示。<br />类似的和@Disabled一样的注解有很多:

@Test @EnabledOnOs(OS.WINDOWS) void testWindows() { assertEquals(“C:\test.ini”, config.getConfigFile(“test.ini”)); }

@Test @EnabledOnOs({ OS.LINUX, OS.MAC }) void testLinuxAndMac() { assertEquals(“/usr/local/test.cfg”, config.getConfigFile(“test.cfg”)); }

`` 以上@EnabledOnOs表示在哪个操作系统上运行。<br />只能在Java 9或更高版本执行的测试,可以加上@DisabledOnJre(JRE.JAVA8)`:
只能在64位操作系统上执行的测试,可以用EnabledIfSystemProperty(named = “os.arch”, matches = “. _64.
“)