【问题标题】:NPE when calling a mocked object (Mockito)调用模拟对象时的 NPE (Mockito)
【发布时间】:2016-11-05 19:22:08
【问题描述】:

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

我特别想模拟“builder.get()”的结果。但是当调用“builder.get()”时,我得到了一个空指针异常(builder 为空)。

我的控制器看起来像:

@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 的示例,我只找到了它返回字符串的示例。

【问题讨论】:

  • 一个问题:在你的测试中,Mockito.when(auskunftClientService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock); 应该是Mockito.when(someService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock); 吗?
  • 好的,改了,谢谢
  • 1 您从哪里获得 NPE? 2 我在代码MockitoAnnotations.initMocks(this); 中看不到任何地方来初始化你的模拟;您是否使用其他跑步者,例如MockitoJUnitRunner3 您可以使用configure a mock to return a whole hierarchy of mocks/stubs 代替默认值(null、false、0 等)。这允许模拟配置(甚至是中间配置)绕过自己创建中间模拟的需要
  • 您现在可以看到带有我使用的注释的完整类。

标签: mocking mockito


【解决方案1】:

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

调用了方法myClientService.getHeaderParams(SomeHeaderParams):我没有看到该调用的任何模拟配置,因此它应该返回null,并且当调用buildRequest(String, Map, Map) 方法时,它应该接收@987654326 @ 作为第二个参数。不符合匹配器 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);
}

【讨论】:

  • 我还必须添加“Mockito.when(myClientService.buildTargetString(Mockito.anyString(), Mockito.anyString())).thenReturn("asd");"不过你的回答是对的,谢谢!:)
【解决方案2】:

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

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

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

【讨论】:

  • 不幸的是,我实际上有这个“Mockito.when(someService.buildRequest(Mockito.anyString(), Mockito.anyMap())).thenReturn(builderMock);”在我的代码中,它只是因为我的混淆而丢失了;)我现在在问题中编辑了我的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
  • 2017-08-21
相关资源
最近更新 更多