模拟方法上的NullPointerException



对于以下方法:

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);
 }
}

相关内容

  • 没有找到相关文章

最新更新