JUnit测试中如何验证methodA的JSONException异常场景?
如何测试
methodA中的JSONException异常分支 我来帮你梳理下问题所在,以及如何正确触发并测试这个异常分支。
你的测试为什么失败?
你当前的测试逻辑存在一个核心问题:你直接mock了整个ClassA实例,然后调用mock对象的methodA方法。这时候执行的是Mockito生成的代理方法,完全不会走你写的真实methodA业务逻辑,自然也就触发不了循环里的JSONException。
而且你的代码逻辑里,formatResponse已经确保YEAR键被添加到response中,正常流程下确实不会抛出异常。要测试这个catch分支,我们需要主动让response.getJSONObject(UtilClass.Object.YEAR)抛出异常。
正确的测试思路与实现
我们需要保留ClassA的真实方法逻辑,同时mockresponse对象的行为,让它在调用getJSONObject时抛出JSONException。这里推荐两种方案:
方案1:使用Mockito Spy+反射注入mock的response
如果不想修改原代码,可以用Spy包装真实实例,再通过反射替换私有成员response:
import org.junit.Test; import org.mockito.Mockito; import java.lang.reflect.Field; import org.json.JSONException; import org.json.JSONObject; public class ClassATest { @Test public void testMethodA_JSONExceptionHandling() throws Exception { // 1. 创建真实的ClassA实例,用Spy包装以保留真实方法逻辑 ClassA classAInstance = Mockito.spy(new ClassA()); // 2. 模拟response对象,让它的getJSONObject方法抛出JSONException JSONObject mockResponse = Mockito.mock(JSONObject.class); Mockito.when(mockResponse.getJSONObject(UtilClass.Object.YEAR)) .thenThrow(new JSONException("Test JSON exception")); // 3. 通过反射将mock的response注入到classAInstance中 Field responseField = ClassA.class.getDeclaredField("response"); responseField.setAccessible(true); responseField.set(classAInstance, mockResponse); // 4. 设置循环需要的computedYear变量(同样用反射,假设它是私有成员) Field computedYearField = ClassA.class.getDeclaredField("computedYear"); computedYearField.setAccessible(true); computedYearField.set(classAInstance, new String[]{"2024"}); // 5. 调用真实的methodA方法 classAInstance.methodA(new JSONObject(), "127.0.0.1"); // 6. 验证异常处理逻辑(比如捕获System.out的输出,或验证日志行为) // 示例:如果用SystemOutRule捕获控制台输出,可以断言包含异常信息 // assertThat(systemOutRule.getLog(), containsString("Test JSON exception")); } }
方案2:修改原代码,让response可注入(更优雅的测试方式)
如果可以调整原代码,给ClassA添加构造方法或setter来注入response,就能避免反射,让测试更简洁:
// 修改后的ClassA代码 public class ClassA { private JSONObject response; private String[] computedYear; // 假设这是类成员变量 // 新增构造方法,方便测试时注入mock的response public ClassA(JSONObject response) { this.response = response; } // 原有的methodA和formatResponse方法... }
对应的测试代码:
@Test public void testMethodA_JSONExceptionHandling() throws JSONException { // 1. 模拟response对象,触发异常 JSONObject mockResponse = Mockito.mock(JSONObject.class); Mockito.when(mockResponse.getJSONObject(UtilClass.Object.YEAR)) .thenThrow(new JSONException("Test JSON exception")); // 2. 创建ClassA实例,注入mock的response ClassA classAInstance = new ClassA(mockResponse); // 3. 设置computedYear变量 Field computedYearField = ClassA.class.getDeclaredField("computedYear"); computedYearField.setAccessible(true); computedYearField.set(classAInstance, new String[]{"2024"}); // 4. 调用方法并验证异常处理 classAInstance.methodA(new JSONObject(), "127.0.0.1"); // 这里可以根据你的异常处理逻辑添加断言,比如验证日志输出或其他副作用 }
额外提示
如果你的异常处理逻辑只是打印控制台信息,可以使用SystemOutRule(需要引入junit-contrib依赖)来捕获并验证输出内容,确保catch块确实被执行了。
内容的提问来源于stack exchange,提问作者Richard Rodjues
相关产品推荐
相关产品推荐

