news 2026/5/31 10:42:52

JUnit4测试生命周期

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JUnit4测试生命周期

JUnit4 测试生命周期详解

概述

理解JUnit4测试生命周期是编写有效单元测试的关键。本文件详细说明测试的执行流程、实例化策略、注解执行顺序等核心概念。

1. 测试生命周期总览

完整的测试执行流程图

┌─────────────────────────────────────────────────────┐
│ 测试类加载 │
├─────────────────────────────────────────────────────┤
│ @BeforeClass 方法执行 │
│ (整个类生命周期只执行一次) │
├─────────────────────────────────────────────────────┤
│ │
│ 对于每个@Test方法: │
│ ┌─────────────────────────────────────────────┐ │
│ │创建新的测试实例│ │
│ ├─────────────────────────────────────────────┤ │
│ │ @Before 方法执行 │ │
│ ├─────────────────────────────────────────────┤ │
│ │ @Test 方法执行 │ │
│ ├─────────────────────────────────────────────┤ │
│ │ 可能执行:@Test(expected) │ │
│ │ 可能执行:@Test(timeout) │ │
│ ├─────────────────────────────────────────────┤ │
│ │ @After 方法执行 │ │
│ │ (即使@Test抛出异常也会执行) │ │
│ └─────────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────┤
│ @AfterClass 方法执行 │
│ (整个类生命周期只执行一次) │
└─────────────────────────────────────────────────────┘

2. 测试类实例化策略

2.1 默认行为:每个测试方法一个实例

JUnit4默认情况下为每个@Test方法创建新的测试实例

importorg.junit.Before;importorg.junit.Test;importstaticorg.junit.Assert.*;publicclassTestInstancePerMethodTest{privateintinstanceCounter=0;publicTestInstancePerMethodTest(){System.out.println("构造函数被调用,创建新实例");instanceCounter=0;// 每次创建新实例时重置}@BeforepublicvoidsetUp(){instanceCounter++;System.out.println("setUp() 执行,instanceCounter: "+instanceCounter);}@TestpublicvoidtestMethod1(){System.out.println("testMethod1 执行,instanceCounter: "+instanceCounter);// 这个实例的instanceCounter是1assertEquals(1,instanceCounter);}@TestpublicvoidtestMethod2(){System.out.println("testMethod2 执行,instanceCounter: "+instanceCounter);// 新的实例,所以instanceCounter也是1assertEquals(1,instanceCounter);}}/* 输出示例: 构造函数被调用,创建新实例 setUp() 执行,instanceCounter: 1 testMethod1 执行,instanceCounter: 1 构造函数被调用,创建新实例 setUp() 执行,instanceCounter: 1 testMethod2 执行,instanceCounter: 1 */

2.2 验证不同实例

publicclassDifferentInstancesTest{privateintinstanceId=(int)(Math.random()*1000);@TestpublicvoidtestInstance1(){System.out.println("testInstance1 - instanceId: "+instanceId);// 保存当前实例IDintcurrentId=instanceId;// 修改实例变量instanceId=999;// 验证修改只影响当前实例assertEquals(999,instanceId);// 在其他测试中这个修改不会生效}@TestpublicvoidtestInstance2(){System.out.println("testInstance2 - instanceId: "+instanceId);// 这是一个新的实例,所以instanceId是新的随机值// 不是999!assertNotEquals(999,instanceId);}}

2.3 为什么每个测试方法创建新实例?

设计目的

  1. 测试隔离:确保测试之间不会相互影响

  2. 线程安全:每个测试在独立的实例上运行

  3. 状态重置:避免测试间的状态污染

3. 注解执行顺序详解

3.1 完整的执行顺序

BeforeClass>{构造函数>Before>Test>After} * N>AfterClass

importorg.junit.*;publicclassFullLifecycleTest{// ===== 类级别生命周期 =====@BeforeClasspublicstaticvoidbeforeClass(){System.out.println("1. @BeforeClass - 类级别初始化");}@AfterClasspublicstaticvoidafterClass(){System.out.println("9. @AfterClass - 类级别清理");}// ===== 实例级别生命周期 =====@Beforepublicvoidbefore(){System.out.println(" 3. @Before - 测试方法前执行");}@Afterpublicvoidafter(){System.out.println(" 5. @After - 测试方法后执行");}// ===== 测试方法 =====@TestpublicvoidtestOne(){System.out.println(" 4. @Test testOne 执行");}@TestpublicvoidtestTwo(){System.out.println(" 4. @Test testTwo 执行");}// ===== 构造函数 =====publicFullLifecycleTest(){System.out.println("2. 构造函数 - 创建测试实例");}}/** * 1. @BeforeClass - 类级别初始化 * 2. 构造函数 - 创建测试实例 * 3. @Before - 测试方法前执行 * 4. @Test testOne 执行 * 5. @After - 测试方法后执行 * 2. 构造函数 - 创建测试实例 * 3. @Before - 测试方法前执行 * 4. @Test testTwo 执行 * 5. @After - 测试方法后执行 * 9. @AfterClass - 类级别清理 */

3.2 异常情况下的生命周期

场景1:@Before抛出异常

@Before异常了,@After还是会执行的,只不过@Test不会执行了

publicclassExceptionInBeforeTest{@BeforepublicvoidsetUp(){System.out.println("@Before 执行");thrownewRuntimeException("@Before 中发生异常");}@AfterpublicvoidtearDown(){System.out.println("@After 执行");}@TestpublicvoidtestMethod(){System.out.println("测试方法执行");fail("这个测试不应该执行");}}/* 输出: @Before 执行 @After 执行 结果:测试失败,@Test方法不会执行,但@After仍然执行 */
场景2:@Test抛出异常

即使@Test报错了,@After还是会执行的

publicclassExceptionInTestTest{@BeforepublicvoidsetUp(){System.out.println("@Before 执行");}@AfterpublicvoidtearDown(){System.out.println("@After 执行(即使@Test抛出异常)");}@Test(expected=RuntimeException.class)publicvoidtestWithExpectedException(){System.out.println("抛出期望的异常");thrownewRuntimeException("测试异常");}@TestpublicvoidtestWithUnexpectedException(){System.out.println("抛出未期望的异常");thrownewRuntimeException("意外异常");}}/* 第一个测试输出: @Before 执行 抛出期望的异常 @After 执行(即使@Test抛出异常) 结果:测试通过(因为异常符合expected) 第二个测试输出: @Before 执行 抛出未期望的异常 @After 执行(即使@Test抛出异常) 结果:测试失败(未期望的异常) */
场景3:@After抛出异常
publicclassExceptionInAfterTest{@TestpublicvoidtestSuccess(){System.out.println("测试成功执行");}@TestpublicvoidtestFailure(){System.out.println("测试失败执行");fail(<
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/29 20:58:14

开箱即用的开源智能体产品全览

开箱即用的开源智能体产品全览 是的&#xff0c;确实有多种开箱即用的开源智能体产品&#xff0c;无需编程或仅需极少配置即可部署运行。 以下是目前市场上主流的开箱即用型开源智能体产品&#xff0c;按使用场景和部署方式分类&#xff1a; 一、通用型零代码智能体平台&…

作者头像 李华
网站建设 2026/5/30 23:41:48

为什么说这款任务编排框架是Java开发者的效率神器?

在当今复杂的业务场景中&#xff0c;如何高效地管理和执行多个相互依赖的任务成为了每个Java开发者必须面对的挑战。TaskFlow任务编排框架应运而生&#xff0c;它基于有向无环图(DAG)的设计理念&#xff0c;为你提供了一套简单易用却又功能强大的任务编排解决方案。无论你是刚入…

作者头像 李华
网站建设 2026/5/29 19:38:48

vue基于Spring Boot的 综合游戏攻略社区论坛交流系统的设计_t8c09gu2

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;同时还支持java、ThinkPHP、Node.js、Spring B…

作者头像 李华
网站建设 2026/5/29 20:51:23

5大付费墙访问工具:从入门到精通的完整指南

你是否曾经遇到过这样的情况&#xff1a;想要阅读一篇精彩的文章&#xff0c;却被付费墙无情地阻挡在外&#xff1f;在当今信息时代&#xff0c;掌握有效的付费墙访问技巧已经成为必备技能。本文将为你详细介绍5款主流的付费墙访问工具&#xff0c;从基础原理到高级应用&#x…

作者头像 李华
网站建设 2026/5/31 3:27:55

10-3 phase:timeout UVM测试平台层次结构与Phase执行顺序解析

文章目录 原始代码及log UVM Phase超时机制与Objection机制深度解析 🔍 分析UVM Phase执行顺序 ✅ UVM Phase执行顺序(核心原则) ✅ 本例关键执行顺序 💡 为什么实际超时是3320ns而不是4100ns? 🧠 核心原因:UVM的phase执行顺序与objection机制 ✅ UVM官方文档确认 �…

作者头像 李华