【问题标题】:Mockito - Unmocked method failed to return the object itselfMockito - Unmocked 方法无法返回对象本身
【发布时间】:2020-04-20 22:18:38
【问题描述】:

我有一个 Spring @RestController,它有一个 Apache Camel 接口 FluentProducerTemplate 的字段。

我正在使用 MockMvc 测试控制器,并且我正在注入 FluentProducerTemplate 作为模拟。

我只想模拟一种方法 - request(),并使用其他方法的真实实现。

但是,我从未模拟的方法中得到 NullPointerException。其他FluentProducerTemplate 方法,它们的返回类型是FluentProducerTemplate。在实现中,它们返回this。模拟对象返回 null。

  1. 我认为 mockito @Mock 只模拟我指定的方法。其他方法使用原始实现。这是正确的说法吗?
  2. 我尝试了@Spy 而不是@Mock,但我得到了同样的错误。
  3. 当我模拟我使用的所有方法时,它都可以工作,而不是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()

【问题讨论】:

    标签: java mockito this


    【解决方案1】:

    您想要所谓的部分模拟。根据您是想主要设置模拟还是主要调用实际实现,有不同的首选方法。

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

    如您所见,第二种方法是编写更多样板。但是,这取决于您的用例,哪种方法更适合。

    【讨论】:

    • 第一种方法抛出 NullPointerExecption。第二种方法 - 我收到此错误:org.mockito.exceptions.base.MockitoException: Cannot call abstract real method on java object! Calling real methods is only possible when mocking non abstract method. //correct example: when(mockOfConcreteClass.nonAbstractMethod()).thenCallRealMethod(); 此外,第二个选项thenCallRealMethod 中缺少括号。
    • 1) Nullpointer 异常的堆栈跟踪是什么? 2) 是的,如果您尝试使用thenCallRealMethod 的方法是abstract,则没有可用的实现,因此您会看到错误。要么提供一个默认实现,要么只是在测试中模拟它。
    • 1) 模拟没有注入,所以我从第一个 withHeader 电话中得到了 NullPointerException。我尝试改用@Spy。然后我又收到了NullPointerException,但来自第二个withHeader 电话。这意味着模拟返回 null 并且没有执行真正的方法。
    • 2) 我在问题中指出 FluentProducerTemplate 是一个接口。你说我必须模拟这种情况下的所有方法?我将尝试模拟接口的实现,看看 Spring 是否知道如何使用 @InjectMocks 将其注入控制器
    • 如果我模拟实现类而不是接口,Spring 无法注入模拟。我将模拟所有方法。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2020-01-21
    • 1970-01-01
    • 2021-03-12
    相关资源
    最近更新 更多