目录
单元测试:是对最小功能单元编写的测试代码。
示例,当开发好一个 Java 阶乘的方法。
n! = 1 x 2 x 3 x ....x n
代码如下:
public static long fact(long n) {
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
需要测试这个方法,一般都在 main 方法执行测试。
public class Main {
public static void main(String[] args) {
System.out.println(Main.fact(3));
}
public static long fact(long n) {
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
}
main 方法做测试有如下缺点:
1、不能把测试代码分离
2、没有打印出测试结果和期望结果
3、比较难编写出通用测试代码
一、Junit
Junit 是一个开源的 Java 语言的单元测试框架。针对 Java 设计,使用广泛。使用 Junit 编写单元测试好处在于:
1、简单地组织测试代码,并随时运行它们。
2、会给出成功与失败结果,还可以生产测试报告,不仅包含测试成功率,还可以统计测试的代码覆盖率(即被测试的代码本身有多少经过测试)
3、单元测试互相独立,不依赖运行顺序
单元测试可以使用断言 Assertions 。断言可以对程序运行的结果做一个判断。
1.1、单元测试初始化与清理资源
一般写单元测试时,当需要初始化数据时可以在方法上使用注解@BeforeEach,当我们测试完成,需要关闭资源时在方法上使用注解@AfterEach。
1.2、捕获异常
package com.demo;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
public class Main {
@Test
public void testException() {
assertThrows(IllegalAccessError.class, ()->{
Main.fact(-1);
});
}
public static long fact(long n) {
if(n < 0) {
throw new IllegalAccessError();
}
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
}
Junit 提供 assertThrows() 来捕获一个指定异常。
第一个参数:异常类型
第二个参数:执行代码,也可以理解发生异常代码。
1.3、条件测试
@EnabledOnOs 是一个条件判断。
示例:在 Windows 和 Linux系统执行不一样的测试方法。
package com.demo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
public class Main {
@Test
@EnabledOnOs(OS.WINDOWS)
void testWindows() {
System.out.println("window");
}
@Test
@EnabledOnOs({ OS.LINUX, OS.MAC })
void testLinuxAndMac() {
System.out.println("linux or mac");
}
}
1.4、标记失效测试方法
可以使用@Disabled注解。
示例
package com.demo;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class Main {
@Test
void test() {
System.out.println("test");
}
@Test
@Disabled
void testDisabled() {
System.out.println("Disabled");
}
}
1.5、参数化测试
如果待测试的输入与输出是一组数据,可以把从测试的数据组织起来,用不同的测试数据调用相同测试方法。
Junit 提供了一个 @ParameterizedTest 注解,用来进行参数化测试。
package com.demo;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class Main {
@ParameterizedTest
@ValueSource(ints = { 0, 1, 5, 100 })
void testAbs(int x) {
assertEquals(x, Math.abs(x));
}
@ParameterizedTest
@ValueSource(ints = { -1, -5, -100 })
void testAbsNegative(int x) {
assertEquals(-x, Math.abs(x));
}
}
另一种传入测试参数的方法是使用@CsvSource,它的每一个字符串表示一行,一行包含的若干参数用,分隔
package com.demo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class Main {
@ParameterizedTest
@CsvSource({ "abc, Abc", "APPLE, Apple", "gooD, Good" })
void testCapitalize(String input, String result) {
System.out.println(input+" "+ result);
}
}