package ua.com.dxrkness.integration; import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.client.RestTestClient; import org.springframework.web.context.WebApplicationContext; import ua.com.dxrkness.service.PopulateService; import ua.com.dxrkness.model.Freight; import java.util.List; import java.util.stream.Stream; import static org.assertj.core.api.BDDAssertions.then; @SpringBootTest @NullMarked class FreightIntegrationTest { private static final int AMOUNT = 100; @Autowired private PopulateService populateService; private RestTestClient testClient; @BeforeEach void setUp(WebApplicationContext context) { populateService.populate(AMOUNT); testClient = RestTestClient.bindToApplicationContext(context).baseUrl("/freights").build(); } @AfterEach void teardown() { populateService.clear(); } private static Stream mediaTypesClientConsumes() { return Stream.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML); } private static Stream mediaTypesClientConsumesProduces() { return Stream.of( Arguments.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON), Arguments.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_XML), Arguments.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML), Arguments.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON) ); } @ParameterizedTest @MethodSource("mediaTypesClientConsumes") void getAll(MediaType mediaType) { // given // when // then testClient.get() .accept(mediaType) .exchange() .expectStatus() .isOk() .expectBody(new ParameterizedTypeReference>() { }) .consumeWith(res -> then(res.getResponseBody()).hasSize(AMOUNT)); } @ParameterizedTest @MethodSource("mediaTypesClientConsumes") void getByIdReturnsEntity(MediaType mediaType) { // given final var id = 1; // when // then testClient.get().uri("/{id}", id) .accept(mediaType) .exchange() .expectStatus() .isOk() .expectBody(Freight.class) .value(val -> { then(val).isNotNull(); then(val.id()).isEqualTo(id); }); } @ParameterizedTest @MethodSource("mediaTypesClientConsumes") void getByIdReturnsNotFound(MediaType mediaType) { // given final var id = -1; // when // then testClient.get().uri("/{id}", id) .accept(mediaType) .exchange() .expectStatus() .isNotFound(); } @ParameterizedTest @MethodSource("mediaTypesClientConsumesProduces") void add(MediaType clientConsumes, MediaType clientProduces) { // given final var newEntity = new Freight(444, "123", "321", 123, new Freight.Dimensions(123, 321, 444), Freight.Status.DELIVERED); // when // then testClient.post() .accept(clientConsumes) .contentType(clientProduces) .body(newEntity) .exchange() .expectStatus() .isOk() .expectBody(Freight.class) .value(val -> { then(val.id()).isEqualTo(AMOUNT+1); then(val).usingRecursiveComparison() .ignoringFields("id") .isEqualTo(newEntity); }); } @ParameterizedTest @MethodSource("mediaTypesClientConsumesProduces") void update(MediaType clientConsumes, MediaType clientProduces) { // given final var existingEntityId = AMOUNT-1; final var newEntity = new Freight(444, "123", "321", 123, new Freight.Dimensions(123, 321, 444), Freight.Status.DELIVERED); // when // then testClient.put().uri("/{id}", existingEntityId) .accept(clientConsumes) .contentType(clientProduces) .body(newEntity) .exchange() .expectStatus() .isOk() .expectBody(Freight.class) .value(val -> { then(val).isNotNull(); then(val.id()).isEqualTo(existingEntityId); then(val).usingRecursiveComparison() .ignoringFields("id") .isEqualTo(newEntity); }); } @ParameterizedTest @MethodSource("mediaTypesClientConsumesProduces") void updatePatch(MediaType clientConsumes, MediaType clientProduces) { // given final var existingEntityId = AMOUNT-1; final var newEntity = new Freight(439, "123", "321", 123, new Freight.Dimensions(123, 321, 444), Freight.Status.DELIVERED); // when // then testClient.patch().uri("/{id}", existingEntityId) .accept(clientConsumes) .contentType(clientProduces) .body(newEntity) .exchange() .expectStatus() .isOk() .expectBody(Freight.class) .value(val -> { then(val).isNotNull(); then(val.id()).isEqualTo(existingEntityId); then(val).usingRecursiveComparison() .ignoringFields("id") .isEqualTo(newEntity); }); } @ParameterizedTest @MethodSource("mediaTypesClientConsumes") void delete(MediaType mediaType) { // given final var existingEntityId = AMOUNT-1; // when // then testClient.delete().uri("/{id}", existingEntityId) .accept(mediaType) .exchange() .expectBody(Freight.class) .value(val -> { then(val).isNotNull(); then(val.id()).isEqualTo(existingEntityId); }); testClient.get().uri("/{id}", existingEntityId) .accept(mediaType) .exchange() .expectStatus() .isNotFound(); } @ParameterizedTest @MethodSource("mediaTypesClientConsumes") void deleteIfEntityNotFound(MediaType mediaType) { // given final var existingEntityId = AMOUNT+1; // when // then testClient.delete().uri("/{id}", existingEntityId) .accept(mediaType) .exchange() .expectStatus() .isNotFound(); } }