#java #spring-boot #spring-boot-test
#java #spring-boot #spring-boot-test
Вопрос:
Я новичок в модульном тестировании. После обращения к Google я создал тестовый класс для тестирования моего контроллера следующим образом:
@RunWith(SpringRunner.class)
@WebMvcTest(PromoController.class)
public class PromoApplicationTests {
@Autowired
protected MockMvc mvc;
@MockBean PromoService promoService;
protected String mapToJson(Object obj) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
@Test
public void applyPromotionTest_1() throws Exception {
String uri = "/classPath/methodPath";
List<Cart> cartLs = new ArrayList<Cart>();
// added few objects to the list
String inputJson = mapToJson(cartLs);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
.contentType(MediaType.APPLICATION_JSON).content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String actual = mvcResult.getResponse().getContentAsString();
String expected = "{"key1":val1, "key2":"val 2"}";
assertEquals(expected, actual, true);
}
}
У меня есть следующий контроллер и класс обслуживания :
@RequestMapping("/classPath")
@RestController
public class PromoController {
@Autowired
PromoService promoService;
@PostMapping("/methodPath")
public PromoResponse applyPromo(@RequestBody List<Cart> cartObj) {
PromoResponse p = promoService.myMethod(cartObj);
return p;
}
}
@Component
public class PromoServiceImpl implements PromoService{
@Override
public PromoResponse myMethod(List<Cart> cartList) {
// myCode
}
}
Когда я отлаживал свой модульный тест, объект p в контроллере был нулевым.
Я получаю статус 200, но не ожидаемый ответ JSON
Чего мне здесь не хватает?
Ответ №1:
При использовании @WebMvcTest загрузка spring будет инициализировать только веб-уровень и не будет загружать полный контекст приложения. И вам нужно использовать @MockBean
для создания и внедрения mock во время использования @WebMvcTest
.
Что вы и сделали
@MockBean
PromoService promoService;
Spring Boot создает экземпляр только веб-уровня, а не всего контекста
Мы используем @MockBean для создания и внедрения макета для GreetingService (если вы этого не сделаете, контекст приложения не сможет запуститься), и мы устанавливаем его ожидания с помощью Mockito.
Но, поскольку это макет компонента, вы несете ответственность за имитацию myMethod()
вызова
@Test
public void applyPromotionTest_1() throws Exception {
String uri = "/classPath/methodPath";
List<Cart> cartLs = new ArrayList<Cart>();
// added few objects to the list
// create PromoResponse object you like to return
When(promoService.myMethod(ArgumentsMatchesr.anyList())).thenReturn(/*PromoResponse object */);
String inputJson = mapToJson(cartLs);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
.contentType(MediaType.APPLICATION_JSON).content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String actual = mvcResult.getResponse().getContentAsString();
String expected = "{"key1":val1, "key2":"val 2"}";
assertEquals(expected, actual, true);
}
Комментарии:
1. Спасибо! Я вижу, что вы упомянули <<// создать объект PromoResponse, который вы хотите вернуть>> . Но разве это не было бы сложным кодированием нашего ответа вместо получения фактического ответа метода POST. Почему требуется жестко закодировать объект PromoResponse?
2. поскольку вы издеваетесь над этим вызовом метода, вы должны вернуть
PromoResponse
@Maha3. Большое вам спасибо @Deadpool