如何用JUnit Mockito测试含JSONObject的函数?解决未Mock问题
org.json.JSONObject not mocked的问题 这个错误是因为Android SDK中的org.json相关类在本地单元测试环境下只是存根(stub)实现,没有实际的功能逻辑,当你在测试中直接调用JSONObject的方法时,就会抛出这个异常。下面给你几种可行的解决办法,你可以根据自己的测试需求选择:
方法1:让测试返回系统类的默认值
在你的app模块的build.gradle文件中,添加测试配置,让未Mock的系统方法返回默认值(比如null、空字符串、0等):
android { // 其他已有的配置... testOptions { unitTests.returnDefaultValues = true } }
这个方法最快捷,但要注意:如果你的测试逻辑依赖于JSON解析的真实结果,可能会因为默认值导致测试逻辑异常,适合简单场景的快速测试。
方法2:引入真实的JSON库替代系统存根
直接在测试依赖中引入独立的org.json库,这样测试环境会使用真实的JSON解析实现,而不是SDK的存根:
dependencies { // 其他依赖... testImplementation 'org.json:json:20230618' }
这个方法不需要修改测试逻辑,直接就能让你的现有测试代码正常运行,适合需要验证真实JSON解析逻辑的场景。
方法3:Mock JSONObject调用(更符合单元测试隔离原则)
如果你的目标是测试getChartTypeJS的逻辑,而不是JSON解析本身,最好的方式是Mock掉JSONObject的相关调用,隔离对JSON库的依赖。步骤如下:
开启Mockito对final类的支持:
在src/test/resources/mockito-extensions目录下创建一个名为org.mockito.plugins.MockMaker的文件,内容写:mock-maker-inline因为
JSONObject是final类,Mockito默认不能Mock,这个配置可以让Mockito支持Mock final类。重构待测试代码,抽离JSONObject创建逻辑:
在LoadJsonData类中添加一个protected方法,把new JSONObject(jsonString)的逻辑抽出来,方便Mock:protected JSONObject createJSONObject(String json) throws JSONException { return new JSONObject(json); }然后修改
getChartTypeJS方法,调用这个新方法:public String getChartTypeJS() { jsonString = getJsonData(); try { JSONObject jsonObject = createJSONObject(jsonString); JSONObject javascriptEvent_JsonObject = jsonObject.getJSONObject("javascript_events"); return javascriptEvent_JsonObject.getString("chartType"); } catch (JSONException e) { e.printStackTrace(); } return ""; }修改测试代码,Mock相关对象:
@RunWith(MockitoJUnitRunner.class) public class LoadJsonData_Test { @Spy private LoadJsonData loadJsonData; @Mock private JSONObject mockRootJson; @Mock private JSONObject mockJavascriptEventsJson; @Test public void getChartTypeJS_test() throws JSONException { // 模拟getJsonData返回的字符串(这里可以是任意结构,因为我们会Mock解析过程) String mockJsonStr = "{\"javascript_events\": {\"chartType\": \"test\"}}"; doReturn(mockJsonStr).when(loadJsonData).getJsonData(); // Mock JSONObject的创建和方法调用 doReturn(mockRootJson).when(loadJsonData).createJSONObject(anyString()); when(mockRootJson.getJSONObject("javascript_events")).thenReturn(mockJavascriptEventsJson); when(mockJavascriptEventsJson.getString("chartType")).thenReturn("javascript:setChartSeriesType(%d);"); // 断言结果 assertEquals(loadJsonData.getChartTypeJS(), "javascript:setChartSeriesType(%d);"); } }这种方式完全隔离了真实的JSON解析逻辑,只测试
getChartTypeJS方法的流程,更符合单元测试的核心思想。
内容的提问来源于stack exchange,提问作者Sindhu

