调用模拟对象时的NPE(Mockito)

时间:2016-07-04 06:41:09

标签: mocking mockito

我在调用由我的模拟服务的另一个模拟方法返回的对象的模拟方法时遇到问题。

特别是我想模仿" builder.get()"的结果。但是当" builder.get()"我被调用,我得到一个空指针异常(构建器为空)。

我的控制器看起来像:

@RestController
public class MyController {

@Autowired
MyClientService myClientService;

@RequestMapping("/myMethod")
@Validated
public MyCustomResponse myMethod(@RequestParam String someId, @Valid @ModelAttribute("someParams") SomeHeaderParams someHeaderParams) {
    final String targetString = myClientService.buildTargetString("resource", someId + "/myMethod");
    final Map<String, String> headerMap = myClientService.getHeaderParams(someHeaderParams);

    Map<String, String> paramsMap = new HashMap<>();
    paramsMap.put("SOME_ID", someId);

    Invocation.Builder builder = myClientService.buildRequest(targetString, headerMap, paramsMap);
    final Response response = builder.get();
    return response.readEntity(MyCustomResponse.class);
}

}

我的测试看起来像:

@RunWith(MockitoJUnitRunner.class)
public class MyControllerTests {

@Spy
@InjectMocks
MyController myControllerController;

@Mock
MyClientService myClientService;

SomeHeaderParams someHeaderParams;

@Before
public void init() {
    someHeaderParams = new SomeHeaderParams();
    someHeaderParams.setCommunicationLanguage("de");
    someHeaderParams.setCrId("123");
    someHeaderParams.setMemberUserId("qwe");
}

@Test

public void myTest() {
    MyCustomResponse myResponseMock = mock(MyCustomResponse.class);
    Response responseMock = mock(Response.class);
    Mockito.when(responseMock.readEntity(MyCustomResponse.class)).thenReturn(myResponseMock);

    Invocation.Builder builderMock = mock(Invocation.Builder.class);
    Mockito.when(builderMock.get()).thenReturn(responseMock);
    Mockito.when(myClientService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock);
    MyCustomResponse response = myControllerController.myMethod("myBusinessId", someHeaderParams);
}

} 这不应该太难,但我没有找到任何模拟方法返回另一个Mock的例子,我只找到了返回String的例子。

2 个答案:

答案 0 :(得分:1)

myMethod(String someId, SomeHeaderParams someHeaderParams)类中MyController的第二行:

调用方法myClientService.getHeaderParams(SomeHeaderParams):我没有看到该调用的任何模拟配置,所以它应该返回null,而当buildRequest(String, Map, Map)方法是在调用时,它应该将null作为第二个参数。匹配器anyMap()未得到满足,这就是它返回默认值null而不是Invocation.Builder类的已配置模拟的原因。

解决方案可以在测试中包含以下内容:

Mockito.when(myClientService.getHeaderParams(Mockito.any(SomeHeaderParams.class))).thenReturn(new HashMap<String, String>());

像这样:

@Test
public void myTest() {
    MyCustomResponse myResponseMock = mock(MyCustomResponse.class);
    Response responseMock = mock(Response.class);
    Mockito.when(responseMock.readEntity(MyCustomResponse.class)).thenReturn(myResponseMock);

    Invocation.Builder builderMock = mock(Invocation.Builder.class);
    Mockito.when(builderMock.get()).thenReturn(responseMock);
    Mockito.when(myClientService.getHeaderParams(Mockito.any(SomeHeaderParams.class))).thenReturn(new HashMap<String, String>());
    Mockito.when(myClientService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock);
    MyCustomResponse response = myControllerController.myMethod("myBusinessId", someHeaderParams);
}

答案 1 :(得分:0)

使用Mockito,您可以配置您的模拟以返回您想要的任何内容,因此您实际上可以配置模拟方法来返回另一个模拟。

查看问题的代码,我发现了一个重要的区别。

在MyController类中,方法a()的第三行是:

final Invocation.Builder builder = someService.buildRequest(targetString, someMap);

在测试类中,第七行测试方法,mock配置如下:

Mockito.when(someService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock);

因此,MyController类中使用的方法是buildRequest(String, Map),但模拟方法是buildRequest(String, Map, Map),这与MyController实际使用的方法不同。

如果用以下代码替换测试中的那一行,它应该可以正常工作:

Mockito.when(someService.buildRequest(Mockito.anyString(), Mockito.anyMap())).thenReturn(builderMock);