add all integration tests. add patch method

This commit is contained in:
2025-11-27 05:29:07 +02:00
parent 45200d394d
commit 795d01b737
7 changed files with 598 additions and 24 deletions

View File

@@ -43,6 +43,11 @@ public class FreightController {
return ResponseEntity.ok(service.update(id, newFreight));
}
@PatchMapping("/{id}")
public ResponseEntity<Freight> updatePatch(@PathVariable("id") long id, @RequestBody Freight newFreight) {
return ResponseEntity.ok(service.update(id, newFreight));
}
@DeleteMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
public ResponseEntity<Freight> delete(@PathVariable("id") long id) {
return ResponseEntity.ofNullable(service.delete(id));

View File

@@ -50,6 +50,11 @@ public class RouteController {
return ResponseEntity.ok(service.update(id, newRoute));
}
@PatchMapping("/{id}")
public ResponseEntity<Route> updatePatch(@PathVariable("id") long id, @RequestBody Route newRoute) {
return ResponseEntity.ok(service.update(id, newRoute));
}
@GetMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
public ResponseEntity<Route> getById(@PathVariable("id") long id) {
return ResponseEntity.ofNullable(service.getById(id));

View File

@@ -43,6 +43,11 @@ public class VehicleController {
return ResponseEntity.ok(service.update(id, newVehicle));
}
@PatchMapping("/{id}")
public ResponseEntity<Vehicle> updatePatch(@PathVariable("id") long id, @RequestBody Vehicle newVehicle) {
return ResponseEntity.ok(service.update(id, newVehicle));
}
@DeleteMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
public ResponseEntity<Vehicle> delete(@PathVariable("id") long id) {
return ResponseEntity.ofNullable(service.delete(id));

View File

@@ -1,8 +1,7 @@
package ua.com.dxrkness.controller;
package ua.com.dxrkness.service;
import org.jspecify.annotations.NullMarked;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Service;
import ua.com.dxrkness.model.Freight;
import ua.com.dxrkness.model.Route;
import ua.com.dxrkness.model.Vehicle;
@@ -12,24 +11,21 @@ import ua.com.dxrkness.repository.VehicleRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
@RequestMapping("/populate")
@Service
@NullMarked
public class PopulateController {
public class PopulateService {
private final FreightRepository freightRepository;
private final RouteRepository routeRepository;
private final VehicleRepository vehicleRepository;
public PopulateController(FreightRepository freightRepository, RouteRepository routeRepository, VehicleRepository vehicleRepository) {
public PopulateService(FreightRepository freightRepository, RouteRepository routeRepository, VehicleRepository vehicleRepository) {
this.freightRepository = freightRepository;
this.routeRepository = routeRepository;
this.vehicleRepository = vehicleRepository;
}
@GetMapping
public ResponseEntity<String> populate(@RequestParam("vals") int vals) {
public void populate(int vals){
var allFreights = new ArrayList<Freight>(vals);
for (int i = 0; i < vals; i++) {
var f = new Freight(i);
@@ -46,16 +42,11 @@ public class PopulateController {
for (int i = 0; i < vals; i++)
routeRepository.add(new Route(i, allVehicles.get(i), List.of(allFreights.get(i))));
return ResponseEntity.ok("success");
}
@DeleteMapping
public ResponseEntity<String> delete() {
public void clear() {
routeRepository.deleteAll();
freightRepository.deleteAll();
vehicleRepository.deleteAll();
return ResponseEntity.ok("success");
}
}

View File

@@ -6,11 +6,13 @@ 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;
@@ -21,20 +23,21 @@ import static org.assertj.core.api.BDDAssertions.then;
@SpringBootTest
@NullMarked
class FreightIntegrationTest {
private RestTestClient testClient;
private RestTestClient populateClient;
private static final int AMOUNT = 100;
@Autowired
private PopulateService populateService;
private RestTestClient testClient;
@BeforeEach
void setUp(WebApplicationContext context) {
populateClient = RestTestClient.bindToApplicationContext(context).baseUrl("/populate").build();
populateClient.get().uri("?vals=%d".formatted(AMOUNT)).exchange();
populateService.populate(AMOUNT);
testClient = RestTestClient.bindToApplicationContext(context).baseUrl("/freights").build();
}
@AfterEach
void teardown() {
populateClient.delete().exchange();
populateService.clear();
}
private static Stream<MediaType> mediaTypesClientConsumes() {
@@ -64,7 +67,7 @@ class FreightIntegrationTest {
.isOk()
.expectBody(new ParameterizedTypeReference<List<Freight>>() {
})
.consumeWith(res -> then(res.getResponseBody()).hasSizeGreaterThan(0));
.consumeWith(res -> then(res.getResponseBody()).hasSize(AMOUNT));
}
@ParameterizedTest
@@ -81,7 +84,10 @@ class FreightIntegrationTest {
.expectStatus()
.isOk()
.expectBody(Freight.class)
.isEqualTo(new Freight(1));
.value(val -> {
then(val).isNotNull();
then(val.id()).isEqualTo(id);
});
}
@ParameterizedTest
@@ -104,6 +110,7 @@ class FreightIntegrationTest {
void add(MediaType clientConsumes, MediaType clientProduces) {
// given
final var newEntity = new Freight(444);
final var expected = new Freight(AMOUNT + 1);
// when
// then
@@ -115,7 +122,7 @@ class FreightIntegrationTest {
.expectStatus()
.isOk()
.expectBody(Freight.class)
.isEqualTo(new Freight(AMOUNT + 1));
.isEqualTo(expected);
}
@ParameterizedTest
@@ -144,6 +151,32 @@ class FreightIntegrationTest {
});
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumesProduces")
void updatePatch(MediaType clientConsumes, MediaType clientProduces) {
// given
final var existingEntityId = AMOUNT-1;
final var newEntity = new Freight(432);
// 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) {
@@ -167,4 +200,19 @@ class FreightIntegrationTest {
.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();
}
}

View File

@@ -0,0 +1,302 @@
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.model.Freight;
import ua.com.dxrkness.model.Route;
import ua.com.dxrkness.model.Vehicle;
import ua.com.dxrkness.service.PopulateService;
import java.util.List;
import java.util.stream.Stream;
import static org.assertj.core.api.BDDAssertions.then;
@SpringBootTest
@NullMarked
class RouteIntegrationTest {
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("/routes").build();
}
@AfterEach
void teardown() {
populateService.clear();
}
private static Stream<MediaType> mediaTypesClientConsumes() {
return Stream.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
}
private static Stream<Arguments> 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<List<Route>>() {
})
.consumeWith(res -> then(res.getResponseBody()).hasSize(AMOUNT));
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumes")
void getByVehicleIdReturnsEntity(MediaType mediaType) {
// given
int vehicleId = 1;
// when
// then
testClient.get().uri(b -> b.queryParam("vehicleId", vehicleId).build())
.accept(mediaType)
.exchangeSuccessfully()
.expectStatus()
.isOk()
.expectBody(new ParameterizedTypeReference<List<Route>>() {
})
.value(val -> then(val).isNotNull()
.hasSize(1)
.allSatisfy(route -> {
then(route.vehicle()).isNotNull();
then(route.vehicle().id()).isEqualTo(vehicleId);
}));
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumes")
void getByVehicleIdReturns404(MediaType mediaType) {
// given
int vehicleId = AMOUNT + 1;
// when
// then
testClient.get().uri(b -> b.queryParam("vehicleId", vehicleId).build())
.accept(mediaType)
.exchangeSuccessfully()
.expectStatus()
.isOk()
.expectBody(List.class)
.isEqualTo(List.of());
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumes")
void getByFreightIdReturnsEntity(MediaType mediaType) {
// given
int freightId = 1;
// when
// then
testClient.get().uri(b -> b.queryParam("freightId", freightId).build())
.accept(mediaType)
.exchangeSuccessfully()
.expectStatus()
.isOk()
.expectBody(new ParameterizedTypeReference<List<Route>>() {
})
.value(val -> then(val).isNotNull()
.hasSize(1)
.allSatisfy(route -> then(route.freights())
.isNotNull()
.isNotEmpty()
.anySatisfy(fre -> then(fre.id()).isEqualTo(freightId))));
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumes")
void getByFreightIdReturns404(MediaType mediaType) {
// given
int freightId = AMOUNT + 1;
// when
// then
testClient.get().uri(b -> b.queryParam("freightId", freightId).build())
.accept(mediaType)
.exchangeSuccessfully()
.expectStatus()
.isOk()
.expectBody(List.class)
.isEqualTo(List.of());
}
@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(Route.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
var veh = new Vehicle(1);
var fre = List.of(new Freight(1));
final var newEntity = new Route(444, veh, fre);
final var expected = new Route(AMOUNT + 1, veh, fre);
// when
// then
testClient.post()
.accept(clientConsumes)
.contentType(clientProduces)
.body(newEntity)
.exchange()
.expectStatus()
.isOk()
.expectBody(Route.class)
.isEqualTo(expected);
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumesProduces")
void update(MediaType clientConsumes, MediaType clientProduces) {
// given
final var existingEntityId = AMOUNT - 1;
final var newEntity = new Route(432, new Vehicle(1), List.of(new Freight(1)));
// when
// then
testClient.put().uri("/{id}", existingEntityId)
.accept(clientConsumes)
.contentType(clientProduces)
.body(newEntity)
.exchange()
.expectStatus()
.isOk()
.expectBody(Route.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 Route(432, new Vehicle(1), List.of(new Freight(1)));
// when
// then
testClient.patch().uri("/{id}", existingEntityId)
.accept(clientConsumes)
.contentType(clientProduces)
.body(newEntity)
.exchange()
.expectStatus()
.isOk()
.expectBody(Route.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(Route.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();
}
}

View File

@@ -0,0 +1,218 @@
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.model.Vehicle;
import ua.com.dxrkness.service.PopulateService;
import java.util.List;
import java.util.stream.Stream;
import static org.assertj.core.api.BDDAssertions.then;
@SpringBootTest
@NullMarked
class VehicleIntegrationTest {
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("/vehicles").build();
}
@AfterEach
void teardown() {
populateService.clear();
}
private static Stream<MediaType> mediaTypesClientConsumes() {
return Stream.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
}
private static Stream<Arguments> 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<List<Vehicle>>() {
})
.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(Vehicle.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 Vehicle(444);
final var expected = new Vehicle(AMOUNT + 1);
// when
// then
testClient.post()
.accept(clientConsumes)
.contentType(clientProduces)
.body(newEntity)
.exchange()
.expectStatus()
.isOk()
.expectBody(Vehicle.class)
.isEqualTo(expected);
}
@ParameterizedTest
@MethodSource("mediaTypesClientConsumesProduces")
void update(MediaType clientConsumes, MediaType clientProduces) {
// given
final var existingEntityId = AMOUNT-1;
final var newEntity = new Vehicle(432);
// when
// then
testClient.put().uri("/{id}", existingEntityId)
.accept(clientConsumes)
.contentType(clientProduces)
.body(newEntity)
.exchange()
.expectStatus()
.isOk()
.expectBody(Vehicle.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 Vehicle(432);
// when
// then
testClient.patch().uri("/{id}", existingEntityId)
.accept(clientConsumes)
.contentType(clientProduces)
.body(newEntity)
.exchange()
.expectStatus()
.isOk()
.expectBody(Vehicle.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(Vehicle.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();
}
}