问题描述
我有这个类定义
@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
where Reservation is a simple 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["location"])
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.mockito.internal.debugging.LocationImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: 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"])
如何以正确的方式注入预订?
How can I inject reservation in the right way??
谢谢
推荐答案
您收到错误是因为当您使用 @MockBean
(或 @Mock
在非Spring 环境)你得到一个 Mockito 模拟对象.此对象是您的对象的空心代理.代理具有与您的类相同的公共方法,并且默认返回其返回类型的默认值(例如,对象为 null,整数为 1 等)或对 void 方法不执行任何操作.
You're getting the error because when you use @MockBean
(or @Mock
in a non Spring environment) you get a Mockito mock object. This object is a hollow proxy of your object.The proxy has the same public methods as your class and by default return the default value of it's return type (e.g. null for objects, 1 for ints, etc.) or does nothing for void methods.
Jackson 抱怨,因为它必须序列化这个没有字段的代理,而 Jackson 不知道该怎么做.
Jackson is complaining because it has to serialize this proxy that has no fields and Jackson does not know what to do.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 否为类 org.mockito.internal.debugging.LocationImpl 找到序列化程序并且没有发现创建 BeanSerializer 的属性(以避免异常,禁用 SerializationFeature.FAIL_ON_EMPTY_BEANS
通常,当您模拟某个要测试的类的依赖项时,您模拟的是在您测试的类中使用的公共方法.直接返回您的依赖项不是一个好的现实世界用例 - 您不太可能必须编写这样的代码.
In general when you mock a dependency of some class that you want to test, you mock it's public methods, that are used in the class that you test.Directly returning your dependency is not a good real world use case - it's very unlikely that you will have to write a code like this.
我猜你正在努力学习,所以让我提供一个改进的例子:
I guess you're trying to learn so let me provide an improved example:
@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
类型的返回和对象.
Instead of directly injecting a value object you usually have a service class that contain some business logic and return something - in my example ReservationService
which have a method getReservation()
that return and object of type Reservation
.
有了它,您可以在测试中模拟 ReservationService
.
Having that, in your test you can mock the 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());
}
}
这篇关于测试 MockBean Null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!