使用JUnit/Mockito测试遗留代码时的HandlerException模拟问题
测试抛出HandlerException的静态方法方案
嘿,针对你遇到的这个测试静态方法抛出自定义异常的问题,我给你整理了几个实用的方案,都是实际项目里常用的:
核心思路
我们的目标很明确:验证当传入的JsonElement不包含ID_TAG时,parse方法确实抛出了预期的HandlerException,并且异常信息和代码里定义的一致。因为这个方法是静态的,而且没有复杂的外部依赖,其实不用Mockito也能轻松搞定,先从最简单的方案说起。
JUnit 5 直接测试方案(最常用)
如果你的项目用的是JUnit 5(现在主流都是这个版本),可以用assertThrows方法直接捕获并验证异常:
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import com.google.gson.JsonElement; import com.google.gson.JsonObject; // 替换成你实际的测试类名 class RecordParserTest { // 替换成你代码里实际的ID_TAG值 private static final String ID_TAG = "id"; @Test void parse_WhenRecordMissingId_ThrowsHandlerException() { // 1. 构造不包含ID_TAG的测试数据 JsonObject emptyRecord = new JsonObject(); JsonElement record = emptyRecord; // 2. 执行方法并捕获异常 HandlerException thrownException = assertThrows(HandlerException.class, () -> { // 替换成你实际的静态方法所在类 RecordParser.parse(record); }); // 3. 验证异常信息是否符合预期 assertEquals("Failed to find Id ...", thrownException.getMessage()); } }
这个方案的好处是简洁直观,assertThrows会自动检查lambda里的代码是否抛出了指定类型的异常,如果没抛出或者抛出了其他类型,测试直接失败。
JUnit 4 兼容方案
如果你的遗留项目还在使用JUnit 4,也有两种方式来测试异常:
方式1:直接指定预期异常
这种方式简单,但没法验证异常信息:
import org.junit.Test; import com.google.gson.JsonElement; import com.google.gson.JsonObject; public class RecordParserTest { private static final String ID_TAG = "id"; @Test(expected = HandlerException.class) public void parse_WhenRecordMissingId_ThrowsHandlerException() throws HandlerException { JsonObject emptyRecord = new JsonObject(); JsonElement record = emptyRecord; RecordParser.parse(record); } }
方式2:用ExpectedException规则验证异常信息
如果需要验证异常内容,就得用JUnit 4的规则类:
import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import com.google.gson.JsonElement; import com.google.gson.JsonObject; public class RecordParserTest { private static final String ID_TAG = "id"; @Rule public ExpectedException exceptionRule = ExpectedException.none(); @Test public void parse_WhenRecordMissingId_ThrowsHandlerExceptionWithCorrectMessage() { // 先声明预期的异常类型和信息 exceptionRule.expect(HandlerException.class); exceptionRule.expectMessage("Failed to find Id ..."); // 执行测试方法 JsonObject emptyRecord = new JsonObject(); JsonElement record = emptyRecord; RecordParser.parse(record); } }
有静态依赖时的Mockito Mock方案
如果你的parse方法里还有其他静态依赖(比如调用了其他静态工具类的方法),这时候才需要用到Mockito的静态Mock功能。比如假设你的方法是这样的:
public static void parse(JsonElement record) throws HandlerException { JsonElement element = record.getAsJsonObject().get(ID_TAG); if(element == null) { throw new HandlerException("Failed to find Id ..."); } // 假设有一个静态方法调用 StaticDataProcessor.process(element); }
测试抛出异常的分支时,我们需要确保静态依赖不会被执行,这时候可以用Mockito的mockStatic:
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import com.google.gson.JsonElement; import com.google.gson.JsonObject; class RecordParserTest { private static final String ID_TAG = "id"; @Test void parse_WhenRecordMissingId_ThrowsHandlerException() { JsonObject emptyRecord = new JsonObject(); JsonElement record = emptyRecord; // 用try-with-resources包裹静态Mock,自动关闭避免影响其他测试 try (MockedStatic<StaticDataProcessor> mockedStatic = mockStatic(StaticDataProcessor.class)) { HandlerException thrownException = assertThrows(HandlerException.class, () -> { RecordParser.parse(record); }); assertEquals("Failed to find Id ...", thrownException.getMessage()); // 验证静态方法没有被调用(因为我们走的是抛出异常的分支) mockedStatic.verify(() -> StaticDataProcessor.process(any(JsonElement.class)), never()); } } }
注意:静态Mock尽量少用,因为它会修改类的静态状态,如果处理不好容易导致测试之间的污染,能用普通测试方案解决的就别用静态Mock。
内容的提问来源于stack exchange,提问作者Nir
相关产品推荐
相关产品推荐

