对于以下方法:
public void parseJSONData(String jsonData) throws JSONException {
if (jsonData == null || jsonData.length() == 0)
throw new JSONException("Empty JSON string");
JSONObject obj = new JSONObject(jsonData);
JSONArray arr = obj.getJSONArray("beacons");
for (int i = 0; i < arr.length(); i++) {
JSONObject item = arr.getJSONObject(i);
addBeaconData(item);
}
}
我写了以下测试方法
@Test
public void testParseJSONData() throws Exception {
String jsonData="testJson";
JSONObject jsonObject = PowerMockito.mock(JSONObject.class);
PowerMockito.whenNew(JSONObject.class).withArguments(jsonData).thenReturn(jsonObject);
JSONArray arr = PowerMockito.mock(JSONArray.class);
PowerMockito.when(jsonObject.getJSONArray(Mockito.anyString())).thenReturn(arr);
JSONObject item = new JSONObject();
PowerMockito.when(arr.length()).thenReturn(1);
PowerMockito.when(arr.getJSONObject(0)).thenReturn(item);
BeaconDataParser jsonParser=PowerMockito.spy(new BeaconDataParser());
PowerMockito.doNothing().when(jsonParser).addBeaconData(item);
jsonParser.parseJSONData(jsonData);
}
结果是带有for循环的行的空指针异常。可能是失败的原因。 arr对象的length方法被模拟。 有2个类注释:
@RunWith(PowerMockRunner.class)
@PrepareForTest({JSONArray.class,JSONObject.class})
答案 0 :(得分:1)
在你的方法中是:
JSONObject obj = new JSONObject(jsonData);
JSONArray arr = obj.getJSONArray(obj);
但在你的测试中是:
PowerMockito.when(jsonObject.getJSONArray(Mockito.anyString())).thenReturn(arr);
您需要调用getJSONArray(使用任何String),但实际上是使用JSONObject调用它
这是NPE的问题,但obj.getJSONArray(obj)
应该做什么?它是否正确?看起来你应该为数据使用一些键,而不是你调用它的对象。
可能错误符合:
JSONArray arr = obj.getJSONArray(obj);
您期望在这里找到什么关键?它应该是:
JSONArray arr = obj.getJSONArray("key for your array");
答案 1 :(得分:0)
在评论中借调Jaroslaw,绝对没有理由让JSON解析中涉及一个模拟框架。 JSON是经过充分指定和经过充分测试的,并且不会成为错误的来源。
相反,将各种beacon JSON字符串传递给您的方法,每次测试一次,并在必要时监视对addBeaconData的调用。但是,对所有测试的最佳测试只是测试对parseJSONData的调用将导致您期望的未模拟的BeaconDataParser 状态。
答案 2 :(得分:0)
也许第二次调用arr.length(),尝试:
public void parseJSONData(String jsonData) throws JSONException {
if (jsonData == null || jsonData.length() == 0)
throw new JSONException("Empty JSON string");
JSONObject obj = new JSONObject(jsonData);
JSONArray arr = obj.getJSONArray("beacons");
int size = arr.length();
for (int i = 0; i < size; i++) {
JSONObject item = arr.getJSONObject(i);
addBeaconData(item);
}
}
答案 3 :(得分:0)
当您模拟方法本地实例化时,您必须在调用该构造函数的 prepareForTest 中添加类名。 这里 BeaconDataParser 是使用new运算符创建 JSONObject 的类。
以下是其他观察结果:
1)不需要在prepareForTest中添加JSONArray.class,JSONObject.class,因为它们只是普通的java对象。
2)JSONObject有多个重载的构造函数,所以你需要在使用whenNew进行模拟时指定参数类型。
您的测试类应该是这样的。
@RunWith(PowerMockRunner.class)
@PrepareForTest({ BeaconDataParser.class })
public class BeaconDataParserTest {
@Test
public void testParseJSONData() throws Exception {
String jsonData = "testJson";
JSONObject jsonObject = PowerMockito.mock(JSONObject.class);
PowerMockito.whenNew(JSONObject.class).withParameterTypes(String.class). withArguments(jsonData)
.thenReturn(jsonObject);
JSONArray arr = PowerMockito.mock(JSONArray.class);
PowerMockito.when(jsonObject.getJSONArray(Mockito.anyString()))
.thenReturn(arr);
JSONObject item = new JSONObject();
PowerMockito.when(arr.length()).thenReturn(1);
PowerMockito.when(arr.getJSONObject(0)).thenReturn(item);
BeaconDataParser jsonParser = PowerMockito.spy(new BeaconDataParser());
PowerMockito.doNothing().when(jsonParser).addBeaconData(item);
jsonParser.parseJSONData(jsonData);
}
}