Java JUnit 单元测试框架

2025-06-09 13:32:12

Java JUnit 单元测试框架

Java 常用类库

JUnit 是 Java 编程语言中最流行的单元测试框架之一,用于编写和运行可重复的自动化测试。

JUnit 由 Kent Beck 和 Erich Gamma 创建,是 xUnit 家族中的一员。单元测试是指对软件中最小的可测试部分(通常是方法或类)进行检查和验证的过程。

JUnit 的主要特点包括:

提供注解来标识测试方法

提供断言来验证预期结果

支持测试套件(Test Suite)

提供测试运行器(Test Runner)

为什么需要单元测试?

单元测试是现代软件开发中不可或缺的一部分,它带来以下好处:

早期发现问题:在开发过程中就能发现并修复错误

提高代码质量:迫使开发者编写更模块化、可测试的代码

文档作用:测试用例本身就是代码行为的最佳文档

重构安全网:确保修改代码时不会破坏现有功能

减少调试时间:快速定位问题所在

在项目中使用 JUnit

对于 JUnit 5:

org.junit.jupiter

junit-jupiter

5.8.2

test

对于 JUnit 4:

junit

junit

4.13.2

test

JUnit 5 基础

JUnit 5 是最新版本,由三个主要模块组成:

JUnit Platform(测试运行的基础)

JUnit Jupiter(新的编程模型和扩展模型)

JUnit Vintage(支持运行 JUnit 3 和 4 的测试)

基本注解

旧版注解:

@Test:标记一个方法为测试方法

@Before:在每个测试方法前执行

@After:在每个测试方法后执行

@BeforeClass:在所有测试前执行(静态方法)

@AfterClass:在所有测试后执行(静态方法)

@Ignore:忽略测试方法

实例

import org.junit.*;

public class CalculatorTest {

@BeforeClass

public static void setUpBeforeClass() {

System.out.println("Before all tests");

}

@Before

public void setUp() {

System.out.println("Before each test");

}

@Test

public void testAddition() {

Calculator calculator = new Calculator();

int result = calculator.add(2, 3);

Assert.assertEquals(5, result);

}

@Test

@Ignore("Not implemented yet")

public void testSubtraction() {

// 测试代码

}

@After

public void tearDown() {

System.out.println("After each test");

}

@AfterClass

public static void tearDownAfterClass() {

System.out.println("After all tests");

}

}

JUnit 5 是新一代版本,新注解如下:

@BeforeEach 替代 @Before

@AfterEach 替代 @After

@BeforeAll 替代 @BeforeClass

@AfterAll 替代 @AfterClass

@Disabled 替代 @Ignore

实例

import org.junit.jupiter.api.*;

@Test

void testMethod() {

// 测试代码

}

@BeforeEach

void setUp() {

// 每个测试方法运行前执行

}

@AfterEach

void tearDown() {

// 每个测试方法运行后执行

}

@BeforeAll

static void initAll() {

// 所有测试方法运行前执行一次

}

@AfterAll

static void tearDownAll() {

// 所有测试方法运行后执行一次

}

常用断言方法JUnit 提供了丰富的断言方法来验证测试结果:

assertEquals(expected, actual)

assertTrue(condition)

assertFalse(condition)

assertNull(object)

assertNotNull(object)

assertSame(expected, actual) (检查是否为同一对象)

assertNotSame(unexpected, actual)

assertArrayEquals(expectedArray, actualArray)

实例

import static org.junit.jupiter.api.Assertions.*;

@Test

void testAssertions() {

// 相等断言

assertEquals(expected, actual);

// 为真断言

assertTrue(condition);

// 为空断言

assertNull(object);

// 异常断言

assertThrows(ExpectedException.class, () -> {

// 会抛出异常的代码

});

// 超时断言

assertTimeout(Duration.ofMillis(100), () -> {

// 应在指定时间内完成的代码

});

}

编写第一个 JUnit 测试

让我们通过一个简单的例子来学习如何编写 JUnit 测试。

1. 创建被测类

实例

public class Calculator {

public int add(int a, int b) {

return a + b;

}

public int divide(int a, int b) {

if (b == 0) {

throw new ArithmeticException("除数不能为零");

}

return a / b;

}

}

2. 创建测试类

实例

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

private Calculator calculator;

@BeforeEach

void setUp() {

calculator = new Calculator();

}

@Test

void testAdd() {

assertEquals(5, calculator.add(2, 3));

}

@Test

void testDivide() {

assertEquals(2, calculator.divide(6, 3));

}

@Test

void testDivideByZero() {

assertThrows(ArithmeticException.class, () -> {

calculator.divide(1, 0);

});

}

}

JUnit 高级特性

参数化测试

JUnit 5 提供了 @ParameterizedTest 注解,允许使用不同的参数多次运行同一个测试:

实例

@ParameterizedTest

@ValueSource(ints = {1, 2, 3})

void testWithValueSource(int argument) {

assertTrue(argument > 0 && argument < 4);

}

测试生命周期

理解 JUnit 测试生命周期对于编写有效的测试很重要:

@BeforeAll 方法执行(仅一次)

对于每个测试方法:

创建测试类实例

@BeforeEach 方法执行

测试方法执行

@AfterEach 方法执行

@AfterAll 方法执行(仅一次)

测试套件

可以使用 @Suite 注解将多个测试类组合在一起运行:

实例

import org.junit.platform.suite.api.SelectClasses;

import org.junit.platform.suite.api.Suite;

@Suite

@SelectClasses({CalculatorTest.class, AnotherTest.class})

public class TestSuite {

}

最佳实践

测试命名:测试方法名应清晰表达其意图,如 shouldReturnTrueWhenInputIsValid()

单一职责:每个测试方法只测试一个功能点

独立测试:测试之间不应有依赖关系

快速反馈:保持测试快速运行

测试覆盖率:追求合理的覆盖率,但不要盲目追求100%

测试数据:使用有意义的测试数据

避免测试实现细节:测试行为而非实现

常见问题解答

JUnit 4 和 JUnit 5 有什么区别?

主要区别包括:

JUnit 5 需要 Java 8 或更高版本

注解从 org.junit 包移动到 org.junit.jupiter.api 包

@Before 和 @After 改为 @BeforeEach 和 @AfterEach

@BeforeClass 和 @AfterClass 改为 @BeforeAll 和 @AfterAll

JUnit 5 引入了扩展模型替代 JUnit 4 的规则

如何运行 JUnit 测试?

可以通过以下方式运行 JUnit 测试:

在 IDE 中右键点击测试类或方法并选择"运行"

使用 Maven:mvn test

使用 Gradle:gradle test

使用 JUnit 控制台启动器

如何测试私有方法?

通常不建议直接测试私有方法,而是通过测试公有方法来间接测试私有方法。如果必须测试私有方法,可以考虑:

使用反射

将方法改为包私有(无修饰符)并在测试目录下创建相同包结构的测试类

重构代码,将私有方法的逻辑提取到单独的类中

总结

JUnit 是 Java 开发者必备的测试工具,掌握它可以显著提高代码质量和开发效率。从简单的单元测试开始,逐步学习更高级的特性,如参数化测试、测试套件等。记住,好的测试应该像生产代码一样受到重视,保持测试代码的整洁和可维护性同样重要。

Java 常用类库

老精算师揭秘世界杯,冷门频出,如何预测比赛结果?
‎QQ邮箱