JUnit
JUnit是一个开源的Java语言的单元测试框架,专门针对Java设计,使用最广泛。JUnit是事实上的单元测试的标准框架。
当我们已经编写了一个Factorial.java
文件后,我们想对其进行测试,需要编写一个对应的FactorialTest.java
文件,以Test
为后缀是一个惯例,并分别将其放入src
和test
目录中。最后,再添加相应的库。
单元测试中常使用断言方法:
assertEquals(expected, actual)
:期待两者相等assertTrue()
: 期待结果为true
assertFalse()
: 期待结果为false
assertNotNull()
: 期待结果为非null
assertArrayEquals()
: 期待结果为数组并与期望数组每个元素的值均相等使用Fixture
在测试的时候,我们经常遇到一个对象需要初始化,测试完可能还需要清理的情况。如果每个
@Test
方法都写一遍这样的重复代码,显然比较麻烦。
JUnit提供了编写测试前准备、测试后清理的固定代码,我们称之为Fixture。 ``` public class CalculatorTest {Calculator calculator;
@BeforeEach public void setUp() {
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.“)