Mockito - 未模拟的方法无法 return 对象本身
Mockito - Unmocked method failed to return the object itself
我有一个 Spring @RestController
,它有一个 Apache Camel 接口字段 FluentProducerTemplate
。
我正在用 MockMvc
测试控制器,我正在注入 FluentProducerTemplate
作为模拟。
我只想模拟一种方法 - request()
,并使用其他方法的实际实现。
但是,我从未模拟的方法中得到 NullPointerException
。其他 FluentProducerTemplate
方法 n ,他们的 return 类型是 FluentProducerTemplate
。在实施中他们 return this
。模拟对象 returns null.
- 我认为 mockito
@Mock
只模拟我指定的方法。其他方法使用原始实现。这是正确的说法吗?
- 我尝试了
@Spy
而不是 @Mock
,但我得到了同样的错误。
- 当我模拟我使用的所有方法时,它就可以工作并且没有
NullPointerException
。
代码:
REST 控制器:
@RestController
@RequestMapping("/v1/test”)
public class MyController {
@EndpointInject(uri = "direct:main")
private FluentProducerTemplate producerTemplate;
@RequestMapping(value = “/test2”, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public MyResponse testRequest(
@RequestHeader(“id”) String id,
@RequestHeader(“context”) String context,
@RequestBody RequestBody requestBody
) {
MyResponse response = producerTemplate
.withHeader(“id”, id)
.withHeader(“context”, context)
.withBody(requestBody)
.request(MyResponse.class);
return response;
}
测试:
@RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
private MockMvc mockMvc;
@Mock
private FluentProducerTemplate producerTemplateMock;
@InjectMocks
private MyControllerTest myController;
private static MyResponse expectedResultSuccess;
private static String requestString;
private static HttpHeaders allRequestHeaders;
@BeforeClass
public static void setup() {
allRequestHeaders = new HttpHeaders();
allRequestHeaders.set(“id”, “123”);
allRequestHeaders.set(“context”, “ABCD1234”);
allRequestHeaders.set(“Content-Type”, “application/json”);
expectedResultSuccess = new MyResponse(“test”);
requestString = “request”BodyText;
}
@Before
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
}
@Test
public void testSuccess() throws Exception {
mockMvc.perform(post(“/v1/test/test2)
.headers(allRequestHeaders)
.content(requestString))
.andExpect(status().isOk())
}
}
仅当我将以下内容添加到 init()
时测试通过:
when(producerTemplateMock.withHeader(any(), any())).thenReturn(producerTemplateMock);
when(producerTemplateMock.withBody(any())).thenReturn(producerTemplateMock);
我的主要问题是 - 为什么我必须模拟所有方法?
我更喜欢使用 withHeader()
和 withBody()
的原始实现,并且只模拟 request()
.
你想要所谓的部分模拟。根据您是想主要设置模拟还是主要调用真实实现,有不同的首选方法。
1。 spy
用于少量模拟,大部分为实际实现
如果你只想模拟一些方法,否则调用真正的实现:
FluentProducerTemplate producerTemplateMock = spy(FluentProducerTemplate.class);
// Mock implementation
doReturn(expectedResultSuccess).when(producerTemplateMock).request(any());
// All other method call will use the real implementations
2。 mock
大部分是模拟,很少有实际实现
FluentProducerTemplate producerTemplateMock = mock(FluentProducerTemplate.class);
// Mock methods
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
// tell mockito to call the real methods
when(producerTemplateMock.withHeader(any(), any())).thenCallRealMethod;
when(producerTemplateMock.withBody(any())).thenCallRealMethod();
如您所见,第二种方法更适合编写样板文件。但是,这取决于您的用例,哪种方法更适合。
我有一个 Spring @RestController
,它有一个 Apache Camel 接口字段 FluentProducerTemplate
。
我正在用 MockMvc
测试控制器,我正在注入 FluentProducerTemplate
作为模拟。
我只想模拟一种方法 - request()
,并使用其他方法的实际实现。
但是,我从未模拟的方法中得到 NullPointerException
。其他 FluentProducerTemplate
方法 n ,他们的 return 类型是 FluentProducerTemplate
。在实施中他们 return this
。模拟对象 returns null.
- 我认为 mockito
@Mock
只模拟我指定的方法。其他方法使用原始实现。这是正确的说法吗? - 我尝试了
@Spy
而不是@Mock
,但我得到了同样的错误。 - 当我模拟我使用的所有方法时,它就可以工作并且没有
NullPointerException
。
代码:
REST 控制器:
@RestController
@RequestMapping("/v1/test”)
public class MyController {
@EndpointInject(uri = "direct:main")
private FluentProducerTemplate producerTemplate;
@RequestMapping(value = “/test2”, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public MyResponse testRequest(
@RequestHeader(“id”) String id,
@RequestHeader(“context”) String context,
@RequestBody RequestBody requestBody
) {
MyResponse response = producerTemplate
.withHeader(“id”, id)
.withHeader(“context”, context)
.withBody(requestBody)
.request(MyResponse.class);
return response;
}
测试:
@RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
private MockMvc mockMvc;
@Mock
private FluentProducerTemplate producerTemplateMock;
@InjectMocks
private MyControllerTest myController;
private static MyResponse expectedResultSuccess;
private static String requestString;
private static HttpHeaders allRequestHeaders;
@BeforeClass
public static void setup() {
allRequestHeaders = new HttpHeaders();
allRequestHeaders.set(“id”, “123”);
allRequestHeaders.set(“context”, “ABCD1234”);
allRequestHeaders.set(“Content-Type”, “application/json”);
expectedResultSuccess = new MyResponse(“test”);
requestString = “request”BodyText;
}
@Before
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
}
@Test
public void testSuccess() throws Exception {
mockMvc.perform(post(“/v1/test/test2)
.headers(allRequestHeaders)
.content(requestString))
.andExpect(status().isOk())
}
}
仅当我将以下内容添加到 init()
时测试通过:
when(producerTemplateMock.withHeader(any(), any())).thenReturn(producerTemplateMock);
when(producerTemplateMock.withBody(any())).thenReturn(producerTemplateMock);
我的主要问题是 - 为什么我必须模拟所有方法?
我更喜欢使用 withHeader()
和 withBody()
的原始实现,并且只模拟 request()
.
你想要所谓的部分模拟。根据您是想主要设置模拟还是主要调用真实实现,有不同的首选方法。
1。 spy
用于少量模拟,大部分为实际实现
如果你只想模拟一些方法,否则调用真正的实现:
FluentProducerTemplate producerTemplateMock = spy(FluentProducerTemplate.class);
// Mock implementation
doReturn(expectedResultSuccess).when(producerTemplateMock).request(any());
// All other method call will use the real implementations
2。 mock
大部分是模拟,很少有实际实现
FluentProducerTemplate producerTemplateMock = mock(FluentProducerTemplate.class);
// Mock methods
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
// tell mockito to call the real methods
when(producerTemplateMock.withHeader(any(), any())).thenCallRealMethod;
when(producerTemplateMock.withBody(any())).thenCallRealMethod();
如您所见,第二种方法更适合编写样板文件。但是,这取决于您的用例,哪种方法更适合。