====== Tests unitarios y de integración ======
{{ testing.png }} Testing (Fuente: https://katalon.com/resources-center/blog/unit-testing)
---- ===== Tests unitarios ===== ==== Utils ==== Además de las capas ''Service'' y ''Controller'', vamos a suponer también que tenemos algunos métodos de utilidad, por ejemplo para trabajar con fechas. Asi también veremos cómo preparar los test unitarios para esta parte del código. public class DateUtil { public static final String DATE_PATTERN = "dd/MM/yyyy"; public static LocalDate format(String date) { return LocalDate.parse(date, DateTimeFormatter.ofPattern(DATE_PATTERN)); } public static long getDaysBetweenDates(LocalDate startDate, LocalDate endDate) { return Math.abs(startDate.until(endDate, ChronoUnit.DAYS)); } } Asi, para las dos funciones anteriores, podríamos preparar algunos casos que nos permitieran comprobar cómo funciona para diferentes entradas. public class DateUtilTests { @Test public void testFormat() { String dateString = "12/04/2025"; LocalDate actualLocalDate = DateUtil.format(dateString); assertEquals(2025, actualLocalDate.getYear()); assertEquals(4, actualLocalDate.getMonthValue()); assertEquals(12, actualLocalDate.getDayOfMonth()); } @Test public void testGetDaysBetweenDates() { LocalDate startDate = LocalDate.of(2025, 1, 1); LocalDate endDate = LocalDate.of(2025, 3, 1); long actualDays = DateUtil.getDaysBetweenDates(startDate, endDate); assertEquals(59, actualDays); actualDays = DateUtil.getDaysBetweenDates(endDate, startDate); assertEquals(59, actualDays); actualDays = DateUtil.getDaysBetweenDates(startDate, startDate); assertEquals(0, actualDays); } } ==== Capa Service ==== @Service public class CarService { . . . public List getAll(String brand, String model) { List carList; if (brand.isEmpty() && model.isEmpty()) { carList = carRepository.findAll(); } else if (brand.isEmpty()) { carList = carRepository.findByModel(model); } else if (model.isEmpty()) { carList = carRepository.findByBrand(brand); } else { carList = carRepository.findByBrandAndModel(brand, model); } return modelMapper.map(carList, new TypeToken>() {}.getType()); } . . . } En este caso tenemos el método ''getAll'' que toma 2 parámetros para filtrar el listado de vehículos por ''brand'' y/o ''model'', por lo que deberíamos preparar varios casos, uno por cada posibilidad. Sería algo como lo siguiente: * ''getAll("", "")'' * ''getAll(brand, "")'' * ''getAll("", model)'' * ''getAll(brand, model)'' Para lo que necesitemos de la capa Repository, usaremos un objeto ''Mock'' para el que prepararemos nosotros mismos las respuestas según el caso. Algo parecido haremos también para el Bean de ''ModelMapper'' @ExtendWith(MockitoExtension.class) public class CarServiceTests { @InjectMocks private CarService carService; @Mock private CarRepository carRepository; @Mock private ModelMapper modelMapper; @Mock private UserRepository userRepository; @Test public void testGetAll() { List mockCarList = List.of( new Car(1, "Opel", "Corsa", LocalDate.now(), LocalDate.now(), 200, 0.5, 0.34, null), new Car(2, "Ford", "Fiesta", LocalDate.now(), LocalDate.now(), 120, 0.5, 0.34, null), new Car(3, "Ford", "Ka", LocalDate.now(), LocalDate.now(), 100 , 0.2, 0.56, null) ); List mockCarOutDtoList = List.of( new CarOutDto(1, "Opel", "Corsa", 1, 0.5, 0.34), new CarOutDto(2, "Ford", "Fiesta", 1, 0.5, 0.34), new CarOutDto(3, "Ford", "Ka", 2, 0.2, 0.56) ); // Mocks when(carRepository.findAll()).thenReturn(mockCarList); when(modelMapper.map(mockCarList, new TypeToken>() {}.getType())).thenReturn(mockCarOutDtoList); // Listado de coches sin aplicar ningún filtro List carList = carService.getAll("", ""); assertEquals(3, carList.size()); assertEquals("Opel", carList.get(0).getBrand()); assertEquals("Corsa", carList.get(0).getModel()); assertEquals("Ford", carList.get(carList.size() - 1).getBrand()); assertEquals("Ka", carList.get(carList.size() - 1).getModel()); verify(carRepository, times(1)).findAll(); verify(carRepository, times(0)).findByBrand(""); verify(carRepository, times(0)).findByModel(""); verify(carRepository, times(0)).findByBrandAndModel("", ""); } @Test public void testGetAllByBrand() { List mockCarList = List.of( new Car(1, "Opel", "Corsa", LocalDate.now(), LocalDate.now(), 200, 0.5, 0.34, null) ); List mockCarOutDtoList = List.of( new CarOutDto(1, "Opel", "Corsa", 1, 0.5, 0.34) ); // Mocks when(carRepository.findByBrand("Opel")).thenReturn(mockCarList); when(modelMapper.map(mockCarList, new TypeToken>() {}.getType())).thenReturn(mockCarOutDtoList); // Listado de coches aplicando el filtro por brand List carList = carService.getAll("Opel", ""); assertEquals(1, carList.size()); assertEquals("Opel", carList.get(0).getBrand()); assertEquals("Corsa", carList.get(0).getModel()); verify(carRepository, times(0)).findAll(); verify(carRepository, times(0)).findByModel("Opel"); verify(carRepository, times(0)).findByBrandAndModel("Opel", ""); verify(carRepository, times(1)).findByBrand("Opel"); } // TODO testGetAllByModel // TODO testGetAllByBrandAndModel> . . . ==== Capa Controller ==== @GetMapping("/cars") public ResponseEntity> getAll(@RequestParam(value = "brand", defaultValue = "") String brand, @RequestParam(value = "model", defaultValue = "") String model) { logger.info("BEGIN getAll"); List cars = carService.getAll(brand, model); logger.info("END getAll"); return new ResponseEntity<>(cars, HttpStatus.OK); } @WebMvcTest(CarController.class) public class CarControllerTests { @Autowired private MockMvc mockMvc; @Autowired private ObjectMapper objectMapper; @MockBean private CarService carService; @MockBean private UserRepository userRepository; @Test public void testGetAllWithoutParametersReturnOk() throws Exception { List mockCarOutDtoList = List.of( new CarOutDto(1, "Opel", "Corsa", 1, 0.5, 0.34), new CarOutDto(2, "Ford", "Fiesta", 1, 0.5, 0.34), new CarOutDto(3, "Ford", "Ka", 2, 0.2, 0.56) ); when(carService.getAll("", "")).thenReturn(mockCarOutDtoList); MvcResult response = mockMvc.perform(MockMvcRequestBuilders.get("/cars") .accept(MediaType.APPLICATION_JSON_VALUE)) .andExpect(status().isOk()) .andReturn(); String jsonResponse = response.getResponse().getContentAsString(); List carListResponse = objectMapper.readValue(jsonResponse, new TypeReference<>(){}); assertNotNull(carListResponse); assertEquals(3, carListResponse.size()); assertEquals("Opel", carListResponse.get(0).getBrand()); assertEquals("Corsa", carListResponse.get(0).getModel()); } @Test public void testGetAllByBrandReturnOk() throws Exception { List mockCarOutDtoList = List.of( new CarOutDto(1, "Opel", "Corsa", 1, 0.5, 0.34), new CarOutDto(2, "Opel", "Astra", 1, 0.5, 0.34) ); when(carService.getAll("Opel", "")).thenReturn(mockCarOutDtoList); MvcResult response = mockMvc.perform(MockMvcRequestBuilders.get("/cars") .queryParam("brand", "Opel") .accept(MediaType.APPLICATION_JSON_VALUE)) .andExpect(status().isOk()) .andReturn(); String jsonResponse = response.getResponse().getContentAsString(); List carListResponse = objectMapper.readValue(jsonResponse, new TypeReference<>(){}); assertNotNull(carListResponse); assertEquals(2, carListResponse.size()); assertEquals("Opel", carListResponse.get(0).getBrand()); assertEquals("Corsa", carListResponse.get(0).getModel()); } // TODO testGetAllByModelReturnOk // TODO testGetAllByBrandAndModelReturnOk . . . ===== Tests de integración ===== (c) 2025 Santiago Faci