0

0

如何在 JUnit 中测试代码抛出特定异常及自定义消息

碧海醫心

碧海醫心

发布时间:2025-10-04 11:06:02

|

552人浏览过

|

来源于php中文网

原创

如何在 JUnit 中测试代码抛出特定异常及自定义消息

软件开发中,异常处理是代码健壮性的重要组成部分。因此,在单元测试中验证代码是否按预期抛出异常,并检查异常的类型和消息,变得至关重要。本教程将详细介绍在 JUnit 测试中验证代码抛出特定异常及其自定义消息的多种方法。文章涵盖了 JUnit 4 的 @Test(expected=...) 注解的用法与限制,以及更灵活、版本无关的 try-catch 块实现方式,并简要提及了 JUnit 5 的 assertThrows 方法,旨在帮助开发者选择最适合其项目和测试场景的异常断言策略。

1. JUnit 4 的 @Test(expected=...) 注解

junit 4 引入了 @test 注解的一个 expected 参数,允许开发者声明一个测试方法预期会抛出的异常类型。如果测试方法抛出了指定的异常,测试通过;如果抛出了其他异常或没有抛出任何异常,测试失败。

示例代码:

假设我们有一个 B3_E2 类,其中包含一个 getMultiplesOfGivenNumber 方法,当 number 参数为零时会抛出 ArithmeticException。

import org.junit.Test;
import static org.junit.Assert.fail; // 用于演示如果异常未抛出

// 假设这是要测试的业务逻辑类
class B3_E2 {
    public static int getMultiplesOfGivenNumber(int number, int[] array) {
        if (number == 0) {
            throw new ArithmeticException("Number cannot be zero");
        }
        // ... 其他业务逻辑 ...
        return 0; // 简化处理
    }
}

public class JUnit4ExpectedExceptionTest {

    @Test(expected = ArithmeticException.class)
    public void testDivideByZeroWithExpectedAnnotation() {
        // 调用可能抛出异常的方法
        B3_E2.getMultiplesOfGivenNumber(0, new int[]{1, 2, 3});
        // 如果代码执行到这里,说明预期的 ArithmeticException 没有被抛出,测试将失败。
        // @Test(expected=...) 会自动处理这种情况,无需手动调用 fail()。
    }
}

注意事项:

  • 版本限制: expected 参数是 JUnit 4 特有的功能。如果您的开发环境(如 IDE)无法识别此参数,很可能是因为您使用的 JUnit 版本低于 4。
  • 功能限制: @Test(expected=...) 只能断言异常的类型。它无法直接验证异常的具体消息内容、异常原因(cause)或异常对象的其他自定义属性。如果需要进行更细致的检查,需要采用其他测试方法。

2. 使用 try-catch 块进行异常断言

try-catch 块是一种更通用、更灵活的异常测试方法,适用于所有 JUnit 版本(包括 JUnit 3、4 和 5)。它允许开发者捕获到异常对象,并对其进行详细的检查。

示例代码:

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; // 用于明确指示测试失败

// 假设这是要测试的业务逻辑类 (与上文相同)
class B3_E2 {
    public static int getMultiplesOfGivenNumber(int number, int[] array) {
        if (number == 0) {
            throw new ArithmeticException("Number cannot be zero");
        }
        // ... 其他业务逻辑 ...
        return 0; // 简化处理
    }
}

public class TryCatchExceptionTest {

    // 辅助方法,用于模拟数据
    private int[] intervalFromOneToTen() {
        return new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    }

    @Test
    public void testDivideByZeroWithTryCatch() {
        try {
            // 调用可能抛出异常的方法
            B3_E2.getMultiplesOfGivenNumber(0, intervalFromOneToTen());
            // 如果代码执行到这里,说明预期的异常没有被抛出,测试应该失败。
            fail("Expected ArithmeticException was not thrown.");
        } catch (ArithmeticException e) {
            // 捕获到预期的 ArithmeticException,现在可以检查其消息或其他属性
            assertEquals("Number cannot be zero", e.getMessage());
            // 对于更复杂的异常,可以在这里检查更多的属性,例如 cause、自定义字段等。
        } catch (Exception e) {
            // 捕获到其他类型的异常,这不是我们预期的异常类型,测试也应失败。
            fail("Thrown an unexpected exception type: " + e.getClass().getName());
        }
    }
}

优势:

  • 版本无关: 此方法不依赖于特定的 JUnit 版本,具有良好的兼容性。
  • 高度灵活: 开发者可以完全控制捕获到的异常对象,检查其消息、原因、堆轨迹或任何自定义属性。这对于测试包含特定错误码或详细上下文信息的自定义异常尤其有用。
  • 精确控制: 确保只有预期的异常被捕获。如果代码抛出其他类型的异常,或者根本没有抛出异常,测试会明确失败,从而避免误报。

3. JUnit 5 的 assertThrows 方法

对于使用 JUnit 5 的项目,assertThrows 是官方推荐的异常测试方法。它结合了 @Test(expected=...) 的简洁性和 try-catch 的灵活性,通过 Lambda 表达式提供了一种更现代、更易读的异常断言方式。

Haiper
Haiper

一个感知模型驱动的AI视频生成和重绘工具,提供文字转视频、图片动画化、视频重绘等功能

下载

示例代码:

import org.junit.jupiter.api.Test; // JUnit 5 的 @Test 注解
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;

// 假设这是要测试的业务逻辑类 (与上文相同)
class B3_E2 {
    public static int getMultiplesOfGivenNumber(int number, int[] array) {
        if (number == 0) {
            throw new ArithmeticException("Number cannot be zero");
        }
        // ... 其他业务逻辑 ...
        return 0; // 简化处理
    }
}

public class JUnit5AssertThrowsTest {

    // 辅助方法,用于模拟数据
    private int[] intervalFromOneToTen() {
        return new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    }

    @Test
    void testDivideByZeroWithAssertThrows() { // JUnit 5 的 @Test 方法可以不声明为 public
        // 使用 assertThrows 捕获异常
        ArithmeticException thrown = assertThrows(
            ArithmeticException.class, // 期望的异常类型
            () -> B3_E2.getMultiplesOfGivenNumber(0, intervalFromOneToTen()), // 包含可能抛出异常的代码
            "Expected ArithmeticException to be thrown, but it wasn't" // 可选的失败消息
        );

        // 验证异常消息
        assertEquals("Number cannot be zero", thrown.getMessage());
        // 也可以进一步检查异常的其他属性
    }
}

优势:

  • 简洁明了: 语法更现代、更易读,通过 Lambda 表达式直接传入待测试的代码块。
  • 功能强大: assertThrows 方法会返回捕获到的异常对象,允许开发者对其进行详细的断言,如验证消息、原因等。
  • 推荐用法: 对于 JUnit 5 及更高版本,这是官方推荐的异常测试方式。

4. 总结与最佳实践

在选择 JUnit 异常测试方法时,应根据您项目的 JUnit 版本、对异常检查的详细程度以及个人偏好来决定:

  • 对于 JUnit 5 及更高版本: 优先推荐使用 Assertions.assertThrows()。它兼顾了简洁性和灵活性,是现代 JUnit 测试的最佳实践。
  • 对于 JUnit 4:
    • 如果仅需验证异常类型且不关心异常消息或其他属性,可以使用 @Test(expected=...)。
    • 如果需要验证异常消息、异常原因或异常对象的其他复杂属性,或者需要兼容更旧的 JUnit 版本,try-catch 块是最佳选择。
  • 对于所有 JUnit 版本: try-catch 块始终是一个可靠且功能强大的选择,尤其是在需要详细检查异常内容,或者在单个测试方法中需要测试多种异常场景时。

一般注意事项:

  • 断言异常消息: 始终建议断言异常消息。异常消息通常包含关于异常发生原因的宝贵上下文信息,有助于使测试更加精确和健壮,并在测试失败时提供更清晰的诊断信息。
  • 避免过度捕获: 在使用 try-catch 块时,确保只捕获你期望的特定异常类型。捕获通用的 Exception 或 Throwable 可能会掩盖其他意料之外的问题,导致测试误报。
  • 清晰的失败信息: 当使用 fail() 方法时,提供有意义的失败信息,以便在测试失败时能快速定位问题。例如,fail("Expected SpecificException was not thrown.") 比简单的 fail() 更有用。

通过掌握这些异常测试方法,您可以编写出更全面、更健壮的单元测试,确保代码在异常情况下也能按预期行为。

相关专题

更多
软件测试常用工具
软件测试常用工具

软件测试常用工具有Selenium、JUnit、Appium、JMeter、LoadRunner、Postman、TestNG、LoadUI、SoapUI、Cucumber和Robot Framework等等。测试人员可以根据具体的测试需求和技术栈选择适合的工具,提高测试效率和准确性 。

428

2023.10.13

java测试工具有哪些
java测试工具有哪些

java测试工具有JUnit、TestNG、Mockito、Selenium、Apache JMeter和Cucumber。php还给大家带来了java有关的教程,欢迎大家前来学习阅读,希望对大家能有所帮助。

295

2023.10.23

Java 单元测试
Java 单元测试

本专题聚焦 Java 在软件测试与持续集成流程中的实战应用,系统讲解 JUnit 单元测试框架、Mock 数据、集成测试、代码覆盖率分析、Maven 测试配置、CI/CD 流水线搭建(Jenkins、GitHub Actions)等关键内容。通过实战案例(如企业级项目自动化测试、持续交付流程搭建),帮助学习者掌握 Java 项目质量保障与自动化交付的完整体系。

19

2025.10.24

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

202

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

187

2025.11.08

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

366

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

561

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

366

2023.07.18

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 0.9万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号