对于以下方法:
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对象的长度方法进行了仿真。有两个类注释:
@RunWith(PowerMockRunner.class)
@PrepareForTest({JSONArray.class,JSONObject.class})
在您的方法中是:
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");
在评论中引用Jaroslaw,绝对没有理由在JSON解析中使用嘲讽框架。JSON经过了很好的指定和测试,不会成为错误的来源。
相反,将各种信标JSON字符串传递给您的方法,每个测试一个,并在必要时监视对addBeacon Data的调用。不过,最好的测试只是测试对parseJSONData的调用是否会导致您期望的未锁定Beacon DataParser状态。
也许第二次调用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);
}
}
在模拟方法本地实例化时,必须在调用该构造函数的prepareForTest中添加类名。这里BeaconsDataParser是使用新操作符创建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);
}
}