Skip to content
This repository has been archived by the owner on Jul 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #8 from ralf-ueberfuhr-ars/feature/service
Browse files Browse the repository at this point in the history
Split JAX-RS resource and service (separation of concerns)
  • Loading branch information
ralf-ueberfuhr-ars authored Jun 18, 2024
2 parents ca42997 + 9d50837 commit d4aec2e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 20 deletions.
17 changes: 17 additions & 0 deletions customer-api-provider/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-bom</artifactId>
<version>3.26.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -56,6 +63,16 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

}
Original file line number Diff line number Diff line change
Expand Up @@ -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<UUID, Customer> 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<Customer> 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());
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<UUID, Customer> 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<Customer> getAll() {
return this.customers
.values()
.stream();
}

public Stream<Customer> 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<Customer> 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;
}

}
Original file line number Diff line number Diff line change
@@ -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);

}

}
Original file line number Diff line number Diff line change
@@ -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();
}

}
Original file line number Diff line number Diff line change
@@ -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();
}

}

0 comments on commit d4aec2e

Please sign in to comment.