1. 单元测试的基本概念
单元测试(Unit Testing) 是一种软件测试方法,专注于测试程序中的最小可测试单元——通常是单个类或方法。通过单元测试,可以确保每个模块按预期工作,从而提高代码的质量和可靠性。
2.安装和配置 JUnit 5
使用 Maven 配置 JUnit 5
首先,在项目的 pom.xml
文件中添加 JUnit 5 的依赖项。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.myproject</groupId>
<artifactId>my-application</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>My Application</name>
<description>A sample application using Maven and JUnit 5</description>
<dependencies>
<!-- 添加 JUnit 5 依赖 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
3.编写单元测试
示例项目结构
假设我们有一个简单的数学工具类 MathUtils
,我们将为其编写单元测试。
my-maven-project/
├── pom.xml
├── src/
│ ├── main/
│ │ └── java/
│ │ └── com/example/myproject/
│ │ └── MathUtils.java
│ └── test/
│ └── java/
│ └── com/example/myproject/
│ └── MathUtilsTest.java
创建 MathUtils
类
src/main/java/com/example/myproject/MathUtils.java
package com.example.myproject;
public class MathUtils {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
public double divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Cannot divide by zero");
}
return (double) a / b;
}
public int multiply(int a, int b) {
return a * b;
}
}
运行结果:
private MathUtils mathUtils;
@BeforeEach
void setUp() {
mathUtils = new MathUtils();
}
@BeforeEach
注解表示该方法在每个测试方法执行前都会被调用,用于初始化测试对象。
编写测试方法:
-
测试加法
@Test
void testAdd() {
assertEquals(5, mathUtils.add(2, 3), "2 + 3 should equal 5");
}
@Test
注解表示这是一个测试方法。assertEquals(expected, actual, message)
断言期望值与实际值相等,并提供自定义消息。
测试减法:
@Test
void testSubtract() {
assertEquals(-1, mathUtils.subtract(2, 3), "2 - 3 should equal -1");
}
测试除法:
@Test
void testDivide() {
assertEquals(2.5, mathUtils.divide(5, 2), 0.001, "5 / 2 should equal 2.5");
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
mathUtils.divide(1, 0);
});
assertEquals("Cannot divide by zero", exception.getMessage(), "Exception message should be 'Cannot divide by zero'");
}
assertThrows(exceptionType, executable)
断言抛出指定类型的异常。assertEquals(expected, actual, delta, message)
用于比较浮点数时允许一定的误差范围。
高级特性
参数化测试
JUnit 5 支持参数化测试,允许你使用不同的输入数据多次运行同一个测试方法。
package com.example.myproject;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
class MathUtilsTest {
private MathUtils mathUtils;
@BeforeEach
void setUp() {
mathUtils = new MathUtils();
}
@ParameterizedTest(name = "{index} => add({0}, {1}) = {2}")
@MethodSource("addProvider")
void testAdd(int a, int b, int expected) {
assertEquals(expected, mathUtils.add(a, b));
}
private static Stream<Arguments> addProvider() {
return Stream.of(
arguments(2, 3, 5),
arguments(-1, 1, 0),
arguments(0, 0, 0)
);
}
}
动态测试
JUnit 5 允许你在运行时动态生成测试用例。
package com.example.myproject;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.Executable;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
class MathUtilsTest {
private MathUtils mathUtils;
@BeforeEach
void setUp() {
mathUtils = new MathUtils();
}
@TestFactory
Stream<DynamicNode> dynamicTestsFromStream() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
return numbers.stream()
.map(number ->
dynamicTest("multiply " + number + " by 2",
() -> assertEquals(number * 2, mathUtils.multiply(number, 2))
)
);
}
}