Java笔记10 - 单元测试
- 使用最常用的测试矿建JUnit
编写JUnit测试
- 单元测试: 针对最小的功能单元编写测试代码
- Java程序最小的功能单元是方法
- 测试驱动开发: 编写接口 -> 编写测试 -> 编写代码 -> ... -> 一边写 -> 一边测.
- 真是情况: 编写好了实现代码, 需要对已有代码进行测试
JUnit
-
开源测试框架
-
简单组织测试代码, 并随时运行.
-
测试覆盖率, 应该在80%以上.
-
核心测试方法加入
@Test
注解 -
所有带有
@test
的方法标识为测试方法 -
Assertion
断言中定义:assertEquals()
: 第一次参数表示期望, 第二个表示结果assertTrue
: 期望结果为true
assertFalse
: 期望结果为false
assertNotNull
: 期望结果为非null
assertArrayEquals()
: 期望结果为数组, 并与期望数组的每个元素相等
-
assertEquals(double expected, double actual, double delta)
: 指定误差值
单元测试的好处
- 单个方法按照正确预期运行
- 修改方法后只需要确保对应的单元测试通过
- 测试代码作为示例代码, 演示如何调用该方法
- 规范:
- 单元测试代码非常简单, 一眼看懂, 不能为测试代码编写测试
- 单元测试相互独立, 不依赖运行
- 测试时注意边界条件,
0
,null
, 空字符串""
等情况
Fixture
- JUnit提供编写测试前准备, 测试后清理的固定代码, 称为
Fixture
- 标记
@BeforeEach
和@AfterEach
, 运行在@Test
方法前后自动运行 @BeforeAll
和@AfterAll
, 运行在所有@Test
前后运行- 只允许一次
- 只能初始化静态变量
- 只能标注在静态方法上
- 总结:
- 实例变量: 在
@BeforeEach
中初始化, 在@AfterEach
中清理. 因为是不同的实例, 在各个@Test
互不影响 - 静态变量: 在
@BeforeAll
中初始化, 在@AfterAll
中清理, 在各个@Test
中均是唯一实例, 影响各个@Test
方法
- 实例变量: 在
- 每次运行
@Test
方法, 首先创建一个XXXTest
实例@Test
方法内部成员变量独立- 成员遍历状态无法共享
异常测试
assertThrows
来期望捕获一个指定的异常Executable
封装了执行的会产生异常的代码.
@Test
void testNegative() {
assertThrows(IllegalArgumentException.class, new Executable() {
@Override
public void execute() throws Throwable {
Factorial.fact(-1);
}
});
assertThrows(IllegalArgumentException.class, () -> {
Factorial.fact(-1);
});
}
- Java8引入函数式编程, 但方法接口使用
->
条件测试
@disable
to skip this test task- JUnit根据不同的条件注解, 决定是否运行当前的
@Test
方法 @EnabledOnOs
/@DisabledOnOs
: 根据当前操作系统执行测试@EnabledIfSystemProperty
: 根据系统变量执行测试@EnabledIfEnvironmentVariable
: 根据环境变量进行测试@EnabledIfEnvironmentVariable(named = "DEBUG", matches="true")
需要传入环境变量DEBUG=true
- 万能的
@EnableIf
: 可以执行任意的Java语句
参数化测试
- 待测试的输入和输出是同一组数据: 可以把测试数据组织起来, 用不用的测试数据调用相同的测试方法
@ParameterizedTest
: 参数化测试注解, 代替@Test
@ParameterizedTest
@ValueSource(ints = {-1, -5, -100})
void testAbsNegative(int x) {
assertEquals(-x, Math.abs(x));
- 多组参数, 使用
@MethodSource
指定方法源
@ParameterizedTest
@MethodSource
void testCapitalize(String input, String result) {
assertEquals(result, StringUtil.capitalize(input));
}
static List<Arguments> testCapitalize() {
return List.of(
Arguments.arguments("abc", "Abc"),
Arguments.arguments("APPLE", "Apple"),
Arguments.arguments("gooD", "Good")
);
}
-
如果静态方法和测试方法不同,
@MethodSource
允许指定方法名 -
使用
@CsvSource
也可以传入参数 -
每个字符串表示一行
疑问
@EnableIf
不能用