【问题标题】:Testing MockBean Null测试 MockBean Null
【发布时间】:2019-05-15 18:39:55
【问题描述】:

我有这个类定义

@RestController
public class ReservationController {
    @Autowired
    private Reservation reservation;

    @RequestMapping(value = "/reservation", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
    @ResponseBody
    public Reservation getReservation() {

        return reservation;
    }
}

其中 Reservation 是一个简单的 Pojo

public class Reservation {
    private long id;
    private String reservationName;

    public Reservation() {
        super();
        this.id = 333;
        this.reservationName = "prova123";
    }

    public Reservation(long id, String reservationName) {
        super();
        this.id = id;
        this.reservationName = reservationName;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getReservationName() {
        return reservationName;
    }

    public void setReservationName(String reservationName) {
        this.reservationName = reservationName;
    }

    @Override
    public String toString() {
        return "Reservation [id=" + id + ", reservationName=" + reservationName + "]";
    }
}

当我尝试测试这个类时

@WebMvcTest
@RunWith(SpringRunner.class)
public class MvcTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean(name = "reservation")
    private Reservation reservation;

    @Test
    public void postReservation() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.post("/reservation"))
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andExpect(MockMvcResultMatchers.status().isOk());
    }
}

我收到了这个错误:

org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 org.springframework.http.converter.HttpMessageConversionException: 类型定义错误:[简单类型,类 org.mockito.internal.debugging.LocationImpl];嵌套异常是 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.mockito.internal.debugging.LocationImpl 并且没有发现创建 BeanSerializer 的属性(为避免异常,禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS)(通过引用链:spring.boot.usingSpringBoot.entity.Reservation$MockitoMock$980801978["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["location"] )

.... ....

原因:com.fasterxml.jackson.databind.exc.InvalidDefinitionException:找不到类 org.mockito.internal.debugging.LocationImpl 的序列化程序,也没有发现创建 BeanSerializer 的属性(为避免异常,请禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS)(通过引用链:spring.boot.usingSpringBoot.entity.Reservation$MockitoMock$980801978["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["位置"])

如何以正确的方式注入预订?

谢谢

【问题讨论】:

  • 首先,您的 resevation 类是一个简单的 pojo,因此它不包含在 spring 上下文中,这意味着您可能需要创建一个 servie 预订类,它必须使用 Service(或组件)进行注释并且在您的测试类,如果你想模拟你使用 InjectMock 的代码
  • 是的,你是对的......我忘记了 @Component 到 Reservation Class

标签: spring spring-boot testing mockito


【解决方案1】:

您收到错误是因为当您使用 @MockBean(或在非 Spring 环境中使用 @Mock)时,您会得到一个 Mockito 模拟对象。此对象是您的对象的空心代理。代理具有与您的类相同的公共方法,并且默认返回其返回类型的默认值(例如 null 表示对象,1 表示整数等),或者对 void 方法不执行任何操作.

Jackson 抱怨,因为它必须序列化这个没有字段的代理,而 Jackson 不知道该怎么做。

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 否 为类 org.mockito.internal.debugging.LocationImpl 找到序列化程序 并且没有发现创建 BeanSerializer 的属性(以避免 异常,禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS

通常,当您模拟某个要测试的类的依赖项时,您模拟的是在您测试的类中使用的公共方法。 直接返回您的依赖项并不是一个好的现实世界用例 - 您不太可能必须编写这样的代码。

我猜你正在努力学习,所以让我提供一个改进的例子:

@RestController
public class ReservationController {
    @Autowired
    private ReservationService reservationService;     //my chnage here

    @RequestMapping(value = "/reservation", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
    @ResponseBody
    public Reservation getReservation() {

        return reservationService.getReservation();   //my chnage here
    }
}

您通常拥有一个包含一些业务逻辑并返回某些内容的服务类,而不是直接注入一个值对象 - 在我的示例中是 ReservationService,它有一个方法 getReservation(),该方法返回和类型为 Reservation 的对象。

有了这个,在你的测试中你可以模拟ReservationService

@WebMvcTest
@RunWith(SpringRunner.class)
public class MvcTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean(name = "reservation")
    private ReservationService reservationService;    //my chnage here

    @Test
    public void postReservation() throws Exception {
        // You need that to specify what should your mock return when getReservation() is called. Without it you will get null
        when(reservationService.getReservation()).thenReturn(new Reservation()); //my chnage here

        mockMvc.perform(MockMvcRequestBuilders.post("/reservation"))
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andExpect(MockMvcResultMatchers.status().isOk());
    }
}

【讨论】:

  • 非常感谢...我将在我的代码中使用这种结构。
  • 只是为了讨论的乐趣......我也尝试过使用这个方法并且它有效。在@Test 方法中我首先设置了依赖reservationController.setReservation(new Reservation(100,"name1"));
猜你喜欢
  • 2019-11-18
  • 2017-01-18
  • 2020-11-03
  • 2019-08-10
  • 2022-10-20
  • 2018-02-04
  • 2021-05-17
  • 2020-02-28
  • 1970-01-01
相关资源
最近更新 更多