У меня есть определение этого класса
@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: Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.mockito.internal.debugging.LocationImpl]; nested exception is 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"])
.... ....
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"])
Как правильно ввести резервирование?
Спасибо
да, ты прав ... я забыл @Component to Reservation Class
Вы получаете сообщение об ошибке, потому что, когда вы используете @MockBean (или @Mock в среде, отличной от Spring), вы получаете mock-объект Mockito. Этот объект является пустым прокси-сервером вашего объекта. Прокси-сервер имеет те же общедоступные методы, что и ваш класс, и по умолчанию возвращает значение по умолчанию для его возвращаемого типа (например, null для объектов, 1 для int и т. д.) Или ничего не делает для void-методов .
Джексон жалуется, потому что он должен сериализовать этот прокси, у которого нет полей, и Джексон не знает, что делать.
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
В общем, когда вы имитируете зависимость некоторого класса, который хотите протестировать, вы имитируете его общедоступные методы, которые используются в тестируемом классе. Непосредственный возврат вашей зависимости - не лучший вариант использования в реальном мире - очень маловероятно, что вам придется писать такой код.
Думаю, вы пытаетесь учиться, поэтому позвольте мне привести улучшенный пример:
@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 я сначала устанавливаю зависимость BookingController.setReservation (new Reservation (100, "name1"));
Прежде всего, ваш класс резервирования - это простое pojo, поэтому он не охвачен контекстом Spring, это означает, что вам может потребоваться создать класс резервирования servie, который должен быть аннотирован с помощью Service (или компонента). И в вашем тестовом классе, если вы хотите издеваться над своим код, который вы используете InjectMock