diff --git a/customer-api-provider/pom.xml b/customer-api-provider/pom.xml
index 8a725ee..198ea72 100644
--- a/customer-api-provider/pom.xml
+++ b/customer-api-provider/pom.xml
@@ -28,6 +28,13 @@
pom
import
+
+ org.assertj
+ assertj-bom
+ 3.26.0
+ pom
+ import
+
@@ -56,6 +63,16 @@
rest-assured
test
+
+ org.assertj
+ assertj-core
+ test
+
+
+ io.quarkus
+ quarkus-junit5-mockito
+ test
+
io.quarkus
quarkus-hibernate-validator
diff --git a/customer-api-provider/src/main/java/de/schulung/sample/quarkus/Customer.java b/customer-api-provider/src/main/java/de/schulung/sample/quarkus/Customer.java
index ff7165f..ba0a508 100644
--- a/customer-api-provider/src/main/java/de/schulung/sample/quarkus/Customer.java
+++ b/customer-api-provider/src/main/java/de/schulung/sample/quarkus/Customer.java
@@ -2,6 +2,7 @@
import jakarta.json.bind.annotation.JsonbProperty;
import jakarta.json.bind.annotation.JsonbTransient;
+import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
@@ -22,10 +23,12 @@ public class Customer {
@Setter(onMethod_ = @JsonbTransient)
private UUID uuid;
@Size(min = 3, max = 100)
+ @NotNull
private String name;
@JsonbProperty("birth_date") // TODO -> use snake_case globally?
private LocalDate birthdate;
@Pattern(regexp = "active|locked|disabled")
+ @NotNull
private String state;
}
diff --git a/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersResource.java b/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersResource.java
index 604f3dd..4f2eab4 100644
--- a/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersResource.java
+++ b/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersResource.java
@@ -5,38 +5,30 @@
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
+import lombok.RequiredArgsConstructor;
-import java.time.LocalDate;
-import java.time.Month;
-import java.util.*;
+import java.util.Collection;
+import java.util.UUID;
@Path("/customers")
+@RequiredArgsConstructor
public class CustomersResource {
- private final Map customers = new HashMap<>();
-
- {
- var customer = new Customer(
- UUID.randomUUID(),
- "Tom",
- LocalDate.of(2000, Month.DECEMBER, 6),
- "active"
- );
- customers.put(customer.getUuid(), customer);
- }
+ private final CustomersService service;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Collection getCustomers() {
- return customers.values();
+ return service
+ .getAll()
+ .toList();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createCustomer(@Valid Customer customer) {
- customer.setUuid(UUID.randomUUID());
- customers.put(customer.getUuid(), customer);
+ service.createCustomer(customer);
final var location = UriBuilder.fromResource(CustomersResource.class)
.path(CustomersResource.class, "findCustomerById")
.build(customer.getUuid().toString());
@@ -58,14 +50,14 @@ public Response createCustomer(@Valid Customer customer) {
@GET
@Path("/{uuid}")
public Customer findCustomerById(@PathParam("uuid") UUID uuid) {
- return Optional.ofNullable(customers.get(uuid))
- .orElseThrow(NotFoundException::new);
+ return service.getByUuid(uuid)
+ .orElseThrow(NotFoundException::new);
}
@DELETE
@Path("/{uuid}")
public Response deleteCustomerById(@PathParam("uuid") UUID uuid) {
- if (customers.remove(uuid) == null) {
+ if (!service.delete(uuid)) {
throw new NotFoundException();
}
return Response
diff --git a/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersService.java b/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersService.java
new file mode 100644
index 0000000..d833329
--- /dev/null
+++ b/customer-api-provider/src/main/java/de/schulung/sample/quarkus/CustomersService.java
@@ -0,0 +1,63 @@
+package de.schulung.sample.quarkus;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+@ApplicationScoped
+public class CustomersService {
+
+ private final Map customers = new HashMap<>();
+
+ { // TODO replace this?
+ var customer = new Customer(
+ UUID.randomUUID(),
+ "Tom",
+ LocalDate.of(2000, Month.DECEMBER, 6),
+ "active"
+ );
+ customers.put(customer.getUuid(), customer);
+ }
+
+ public Stream getAll() {
+ return this.customers
+ .values()
+ .stream();
+ }
+
+ public Stream getByState(
+ @NotNull
+ @Pattern(regexp = "active|locked|disabled")
+ String state
+ ) {
+ return this.getAll()
+ .filter(c -> c.getState().equals(state));
+ }
+
+ public void createCustomer(@Valid Customer customer) {
+ customer.setUuid(UUID.randomUUID());
+ customers.put(customer.getUuid(), customer);
+ }
+
+ public Optional getByUuid(@NotNull UUID uuid) {
+ return Optional.ofNullable(customers.get(uuid));
+ }
+
+ public boolean exists(@NotNull UUID uuid) {
+ return customers.containsKey(uuid);
+ }
+
+ public boolean delete(@NotNull UUID uuid) {
+ return customers.remove(uuid) != null;
+ }
+
+}
diff --git a/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomerApiMockedServiceTests.java b/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomerApiMockedServiceTests.java
new file mode 100644
index 0000000..777728a
--- /dev/null
+++ b/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomerApiMockedServiceTests.java
@@ -0,0 +1,61 @@
+package de.schulung.sample.quarkus;
+
+import io.quarkus.test.InjectMock;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.Test;
+
+import java.util.Optional;
+import java.util.UUID;
+
+import static io.restassured.RestAssured.given;
+import static org.mockito.Mockito.*;
+
+@QuarkusTest
+public class CustomerApiMockedServiceTests {
+
+ @InjectMock
+ CustomersService service;
+
+ @Test
+ void shouldReturn404WhenCustomerNotExists() {
+
+ var uuid = UUID.randomUUID();
+ when(service.getByUuid(uuid))
+ .thenReturn(Optional.empty());
+
+ given()
+ .when()
+ .accept(ContentType.JSON)
+ .get("/customers/{uuid}", uuid)
+ .then()
+ .statusCode(404);
+
+ verify(service).getByUuid(uuid);
+
+ }
+
+ // TODO: wenn invalider Kunde angelegt werden soll, dann 400 + kein Service-Aufruf
+
+ @Test
+ void shouldNotInvokeServiceWhenInvalidCustomerIsCreated() {
+ given()
+ .when()
+ .contentType(ContentType.JSON)
+ .body("""
+ {
+ "name": "T",
+ "birth_date": "2000-10-04",
+ "state": "active"
+ }
+ """)
+ .accept(ContentType.JSON)
+ .post("/customers")
+ .then()
+ .statusCode(400);
+
+ verifyNoInteractions(service);
+
+ }
+
+}
diff --git a/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomersServiceIntegrationTests.java b/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomersServiceIntegrationTests.java
new file mode 100644
index 0000000..64b001d
--- /dev/null
+++ b/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomersServiceIntegrationTests.java
@@ -0,0 +1,36 @@
+package de.schulung.sample.quarkus;
+
+import io.quarkus.test.junit.QuarkusTest;
+import jakarta.inject.Inject;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@QuarkusTest
+public class CustomersServiceIntegrationTests {
+
+ @Inject
+ CustomersService service;
+
+ // TODO Testfall: Customer anlegen mit zu kurzem Namen -> Validierungsfehler
+
+ @Test
+ void shouldNotCreateInvalidCustomer() {
+ var customer = new Customer();
+ assertThatThrownBy(() -> service.createCustomer(customer))
+ .isNotNull();
+ }
+
+ @Test
+ void shouldNotCreateNullCustomer() {
+ assertThatThrownBy(() -> service.createCustomer(null))
+ .isNotNull();
+ }
+
+ @Test
+ void shouldNotInvokeSearchWithNullUuid() {
+ assertThatThrownBy(() -> service.getByUuid(null))
+ .isNotNull();
+ }
+
+}
diff --git a/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomersServiceTests.java b/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomersServiceTests.java
new file mode 100644
index 0000000..4dcab18
--- /dev/null
+++ b/customer-api-provider/src/test/java/de/schulung/sample/quarkus/CustomersServiceTests.java
@@ -0,0 +1,41 @@
+package de.schulung.sample.quarkus;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.time.Month;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CustomersServiceTests {
+
+ private final CustomersService service = new CustomersService();
+
+ @Test
+ void shouldAddUuidToNewCustomer() {
+ var customer = new Customer();
+ customer.setName("Tom");
+ customer.setBirthdate(LocalDate.of(2000, Month.FEBRUARY, 2));
+ customer.setState("active");
+
+ service.createCustomer(customer);
+
+ assertThat(customer.getUuid())
+ .isNotNull();
+ }
+
+ @Test
+ void shouldFindNewCustomer() {
+ var customer = new Customer();
+ customer.setName("Tom");
+ customer.setBirthdate(LocalDate.of(2000, Month.FEBRUARY, 2));
+ customer.setState("active");
+ service.createCustomer(customer);
+ var uuid = customer.getUuid();
+
+ var result = service.getByUuid(uuid);
+
+ assertThat(result).isNotEmpty();
+ }
+
+}