Junit测试失败:HttpMessageConversion错误

Posted

技术标签:

【中文标题】Junit测试失败:HttpMessageConversion错误【英文标题】:Junit test failure: HttpMessageConversion error 【发布时间】:2021-08-27 08:16:25 【问题描述】:

我正在尝试使用Mockito 为休息网址编写JUnit 测试用例。

@Override
public void sendWebhook(WebRequest webRequest) 
    ResponseEntity<Object> webresponse = restService.sendWebhook(webRequest);

restServiceImpl

@Override
public ResponseEntity<Object> sendWebhook(WebRequest webRequest) 
    ResponseEntity<Object> response = null;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity<webRequest> request = new HttpEntity<>(webRequest, headers);
    try 
        response = restTemplate.exchange(webRequest.getUrl(), HttpMethod.POST, request, Object.class);
     catch (ResourceAccessException resourceAccessException) 

        return null;
    
    return response;

上面的类使用Mockito的单元测试用例

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class WebServiceImplTest 

    @Autowired
    private RestTemplate restTemplate;
    private MockRestServiceServer mockServer;
    @Autowired
    private RestService restService;

    @Before
    public void setUp() 
        MockitoAnnotations.initMocks(this);
        mockServer = MockRestServiceServer.createServer(restTemplate);
    

    @Test
    public void testSendWebhookWithSuccess() throws Exception 
        /* setup mock */
        WebRequest webRequest = mock(WebRequest.class);
        Mockito.when(restService.sendWebhook(webRequest))
                .thenReturn(new ResponseEntity<Object>(HttpStatus.OK));

        UriComponents uriComponents =
                UriComponentsBuilder.fromUriString("http://localhost:8080/mockWeb/sendSuccessMsg").build();
        mockServer.expect(requestTo(uriComponents.toUriString())).andExpect(method(HttpMethod.POST))
                .andRespond(withSuccess("Success", MediaType.APPLICATION_JSON));

        mockServer.verify();
    

当我运行上面的测试用例时,我得到了,

Results :  
Tests in error: 
testSendWebhookWithSuccess » HttpMessageConversion
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0

我遇到错误

Mockito.when(restService.sendWebhook(webRequest))
                .thenReturn(new ResponseEntity<Object>(HttpStatus.OK));

为什么我会遇到错误。我能知道我错过了什么吗

stackTrace 下面附上

    Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 38.087 sec <<< FAILURE! - in ...web.service.impl.WebServiceImplTest
    testSendWebhookWithSuccess(...service.impl.WebServiceImplTest)  Time elapsed: 0.321 sec  <<< ERROR!
    org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.mockito.internal.invocation.mockref.MockWeakReference]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.mockito.internal.invocation.mockref.MockWeakReference and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.equifax.mortgage.udm.webhook.model.WebRequest$MockitoMock$1970556850["mockitoInterceptor"]->org.mockito.internal.creation.bytebuddy.MockMethodInterceptor["mockHandler"]->org.mockito.internal.handler.InvocationNotifierHandler["invocationContainer"]->org.mockito.internal.stubbing.InvocationContainerImpl["invocationForStubbing"]->org.mockito.internal.invocation.InvocationMatcher["invocation"]->org.mockito.internal.invocation.InterceptedInvocation["mockRef"])
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
        at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)
        at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
        at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
        at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
        at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1516)
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1006)
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:343)
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
        at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:943)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:737)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:674)
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:583)
        at ...web.service.impl.RestServiceImpl.sendWebhook(RestServiceImpl.java:50)

【问题讨论】:

将错误堆栈跟踪附加到问题 @Alex 附加堆栈跟踪 据我所知,您正在尝试使用模拟对象调用真实服务。所以RestTemplate 无法序列化它。此外,您还试图在真实服务Mockito.when(restService.sendWebhook(webRequest)) 上模拟方法执行 除了上面的评论:当你想用你的 RestTemplate 发送它时,spring 正在尝试用一个 HttpMessageConverter 转换你的 webrequest。这通常是为了让您可以传入对象,例如将它们转换为 json。是否可以使用普通的 pojo 而不是 WebRequest 作为方法参数? 【参考方案1】:

这意味着您的模拟对象正在通过正确的杰克逊反序列化,而您只能对真实对象执行此操作。 在您的情况下,我认为问题出在new ResponseEntity&lt;Object&gt;(...):它不是真正的可序列化对象。

为您的 thenReturn(thisBetterBeSerializable) 创建一些具体的东西,因为它显然在嵌套服务调用中的某个地方通过 jackson。

当我在 spring 控制器测试中创建一个模拟对象作为响应时,我得到了确切的异常(“没有为类 org.mockito.internal.invocation.mockref.MockWeakReference 和...找到序列化程序”):

我有这个(意译)

@MockBean
private MyService myService;

@Test
public void test_200Returned() throws Exception 
  MyRealResponseType mockResponse = Mockito.mock(MyRealResponseType.class); // WRONG!
  when(myService.myMethod(any(MyRequest.class))).thenReturn(mockResponse);

  this.mockMvc.perform(post("/my/service/api")).andExpect(status().isOk());

一切正常,直到我的控制器类(服务于 /my/service/api 的控制器类)在调用 myService.myMethod 后尝试返回一个对象以获取它。 mockResponse 对象被返回(按计划),但 Jackson 无法处理它。

我解决了我的问题,将我的 Mockito.mock 行替换为:

  MyRealResponseType mockResponse = new MyRealResponseType(); // RIGHT!
  mockResponse.setSomeNeededPropertyJustInCase("someValue");
...

然后一切正常,我的测试通过了。

你的情况略有不同,但我怀疑如果你创建一个真实的对象来传递给thenReturn,你的问题就会消失。

【讨论】:

以上是关于Junit测试失败:HttpMessageConversion错误的主要内容,如果未能解决你的问题,请参考以下文章

JUnit 测试用例中“失败”的实际用途是啥?

Selenium 可以截取 JUnit 测试失败的屏幕截图吗?

竹失败测试无法解析junit

运行 Junit 测试用例时“加载 ApplicationContext 失败”

如何让 JUnit 测试(从 Ant 脚本驱动)转储导致失败的异常堆栈?

Spring MVC 应用程序 Junit 测试用例失败