From 7010533b25dac12eb6b041b502f82a7a3d65094e Mon Sep 17 00:00:00 2001 From: Lukasz Rys Date: Sun, 17 Nov 2019 15:19:28 +0100 Subject: [PATCH] BAEL-2275: Init version --- ddd/docker/.env | 1 + ddd/docker/docker-compose.yml | 14 +++ ddd/docker/mongo-init.js | 12 +++ ddd/pom.xml | 5 + .../ddd/layers/DomainLayerApplication.java | 13 +++ .../layers/application/OrderController.java | 44 +++++++++ .../request/AddProductRequest.java | 18 ++++ .../request/CreateOrderRequest.java | 21 +++++ .../response/CreateOrderResponse.java | 15 +++ .../com/baeldung/ddd/layers/domain/Order.java | 84 +++++++++++++++++ .../ddd/layers/domain/OrderStatus.java | 5 + .../baeldung/ddd/layers/domain/Product.java | 43 +++++++++ .../domain/exception/DomainException.java | 7 ++ .../domain/repository/OrderRepository.java | 12 +++ .../domain/service/DomainOrderService.java | 56 ++++++++++++ .../layers/domain/service/OrderService.java | 16 ++++ .../configuration/DomainConfiguration.java | 16 ++++ .../configuration/MongoDBConfiguration.java | 7 ++ .../repository/MongoDbOrderRepository.java | 30 ++++++ .../repository/SpringDataOrderRepository.java | 10 ++ ddd/src/main/resources/ddd-layers.properties | 5 + .../ddd/layers/domain/OrderProvider.java | 19 ++++ .../ddd/layers/domain/OrderUnitTest.java | 57 ++++++++++++ .../service/DomainOrderServiceUnitTest.java | 91 +++++++++++++++++++ .../MongoDbOrderRepositoryUnitTest.java | 25 +++++ 25 files changed, 626 insertions(+) create mode 100644 ddd/docker/.env create mode 100644 ddd/docker/docker-compose.yml create mode 100644 ddd/docker/mongo-init.js create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/DomainLayerApplication.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/application/OrderController.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/application/request/AddProductRequest.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/application/request/CreateOrderRequest.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/application/response/CreateOrderResponse.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/Order.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/OrderStatus.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/Product.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/exception/DomainException.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/repository/OrderRepository.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/service/DomainOrderService.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/domain/service/OrderService.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/DomainConfiguration.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/MongoDBConfiguration.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepository.java create mode 100644 ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/SpringDataOrderRepository.java create mode 100644 ddd/src/main/resources/ddd-layers.properties create mode 100644 ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderProvider.java create mode 100644 ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderUnitTest.java create mode 100644 ddd/src/test/java/com/baeldung/ddd/layers/domain/service/DomainOrderServiceUnitTest.java create mode 100644 ddd/src/test/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java diff --git a/ddd/docker/.env b/ddd/docker/.env new file mode 100644 index 0000000000..99f7e8b8d4 --- /dev/null +++ b/ddd/docker/.env @@ -0,0 +1 @@ +ORDER_DOCKER_MONGODB_PORT=27017 \ No newline at end of file diff --git a/ddd/docker/docker-compose.yml b/ddd/docker/docker-compose.yml new file mode 100644 index 0000000000..eb27e56061 --- /dev/null +++ b/ddd/docker/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' + +services: + order-mongo-database: + image: mongo:3.4.13 + restart: always + ports: + - ${ORDER_DOCKER_MONGODB_PORT}:27017 + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: admin + MONGO_INITDB_DATABASE: order-database + volumes: + - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro \ No newline at end of file diff --git a/ddd/docker/mongo-init.js b/ddd/docker/mongo-init.js new file mode 100644 index 0000000000..b1564df50a --- /dev/null +++ b/ddd/docker/mongo-init.js @@ -0,0 +1,12 @@ +db.createUser( + { + user: "order", + pwd: "order", + roles: [ + { + role: "readWrite", + db: "order-database" + } + ] + } +); \ No newline at end of file diff --git a/ddd/pom.xml b/ddd/pom.xml index c249007ba4..6571470116 100644 --- a/ddd/pom.xml +++ b/ddd/pom.xml @@ -74,6 +74,11 @@ spring-boot-starter-test test + + org.mockito + mockito-core + test + de.flapdoodle.embed de.flapdoodle.embed.mongo diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/DomainLayerApplication.java b/ddd/src/main/java/com/baeldung/ddd/layers/DomainLayerApplication.java new file mode 100644 index 0000000000..35fb1958e2 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/DomainLayerApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.ddd.layers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource(value={"classpath:ddd-layers.properties"}) +public class DomainLayerApplication { + public static void main(String[] args) { + SpringApplication.run(DomainLayerApplication.class, args); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/application/OrderController.java b/ddd/src/main/java/com/baeldung/ddd/layers/application/OrderController.java new file mode 100644 index 0000000000..fa3576eb37 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/application/OrderController.java @@ -0,0 +1,44 @@ +package com.baeldung.ddd.layers.application; + +import com.baeldung.ddd.layers.application.request.AddProductRequest; +import com.baeldung.ddd.layers.application.request.CreateOrderRequest; +import com.baeldung.ddd.layers.application.response.CreateOrderResponse; +import com.baeldung.ddd.layers.domain.service.OrderService; +import org.bson.types.ObjectId; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/orders") +public class OrderController { + + private final OrderService orderService; + + @Autowired + public OrderController(OrderService orderService) { + this.orderService = orderService; + } + + @PostMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) + CreateOrderResponse createOrder(@RequestBody final CreateOrderRequest createOrderRequest) { + return new CreateOrderResponse(orderService + .createOrder(createOrderRequest.getProducts()) + .toString()); + } + + @PostMapping(value = "/{id}/products", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) + void addProduct(@PathVariable final ObjectId id, @RequestBody final AddProductRequest addProductRequest) { + orderService.addProduct(id, addProductRequest.getProduct()); + } + + @DeleteMapping(value = "/{id}/products", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) + void deleteProduct(@PathVariable final ObjectId id, @RequestParam final String name) { + orderService.deleteProduct(id, name); + } + + @PostMapping("/{id}/complete") + void completeOrder(@PathVariable final ObjectId id) { + orderService.completeOrder(id); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/application/request/AddProductRequest.java b/ddd/src/main/java/com/baeldung/ddd/layers/application/request/AddProductRequest.java new file mode 100644 index 0000000000..823b2191ef --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/application/request/AddProductRequest.java @@ -0,0 +1,18 @@ +package com.baeldung.ddd.layers.application.request; + +import com.baeldung.ddd.layers.domain.Product; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class AddProductRequest { + private Product product; + + @JsonCreator + public AddProductRequest(@JsonProperty("product") final Product product) { + this.product = product; + } + + public Product getProduct() { + return product; + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/application/request/CreateOrderRequest.java b/ddd/src/main/java/com/baeldung/ddd/layers/application/request/CreateOrderRequest.java new file mode 100644 index 0000000000..a2dabd05fc --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/application/request/CreateOrderRequest.java @@ -0,0 +1,21 @@ +package com.baeldung.ddd.layers.application.request; + +import com.baeldung.ddd.layers.domain.Product; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; + +public class CreateOrderRequest { + private List products; + + @JsonCreator + public CreateOrderRequest(@JsonProperty("products") final List productList) { + this.products = new ArrayList<>(productList); + } + + public List getProducts() { + return products; + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/application/response/CreateOrderResponse.java b/ddd/src/main/java/com/baeldung/ddd/layers/application/response/CreateOrderResponse.java new file mode 100644 index 0000000000..d57f297bde --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/application/response/CreateOrderResponse.java @@ -0,0 +1,15 @@ +package com.baeldung.ddd.layers.application.response; + +import org.bson.types.ObjectId; + +public class CreateOrderResponse { + private final String id; + + public CreateOrderResponse(String id) { + this.id = id; + } + + public String getId() { + return id; + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/Order.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/Order.java new file mode 100644 index 0000000000..d69b51ae57 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/Order.java @@ -0,0 +1,84 @@ +package com.baeldung.ddd.layers.domain; + +import com.baeldung.ddd.layers.domain.exception.DomainException; +import org.bson.types.ObjectId; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Order { + private final ObjectId id; + private OrderStatus status; + private List products; + private BigDecimal price; + + public Order(final ObjectId id, final List products) { + this.id = id; + this.products = new ArrayList<>(products); + this.status = OrderStatus.CREATED; + this.price = products + .stream() + .map(Product::getPrice) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + public void complete() { + validateState(); + this.status = OrderStatus.COMPLETED; + } + + public void addProduct(final Product product) { + validateState(); + validateProduct(product); + products.add(product); + price = price.add(product.getPrice()); + } + + public void removeProduct(final String name) { + validateState(); + final Product product = getProduct(name); + products.remove(product); + + price = price.subtract(product.getPrice()); + } + + private Product getProduct(String name) { + return products + .stream() + .filter(product -> product + .getName() + .equals(name)) + .findFirst() + .orElseThrow(() -> new DomainException("Product with " + name + " doesn't exist.")); + } + + private void validateState() { + if (OrderStatus.COMPLETED.equals(status)) { + throw new DomainException("The order is in completed state."); + } + } + + private void validateProduct(final Product product) { + if (product == null) { + throw new DomainException("The product cannot be null."); + } + } + + public ObjectId getId() { + return id; + } + + public OrderStatus getStatus() { + return status; + } + + public List getProducts() { + return Collections.unmodifiableList(products); + } + + public BigDecimal getPrice() { + return price; + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/OrderStatus.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/OrderStatus.java new file mode 100644 index 0000000000..f5d32374be --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/OrderStatus.java @@ -0,0 +1,5 @@ +package com.baeldung.ddd.layers.domain; + +public enum OrderStatus { + CREATED, COMPLETED +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/Product.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/Product.java new file mode 100644 index 0000000000..286585d84a --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/Product.java @@ -0,0 +1,43 @@ +package com.baeldung.ddd.layers.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.math.BigDecimal; +import java.util.Objects; + +public class Product { + private final BigDecimal price; + private final String name; + + @JsonCreator + public Product(@JsonProperty("price") final BigDecimal price, @JsonProperty("name") final String name) { + this.price = price; + this.name = name; + } + + public BigDecimal getPrice() { + return price; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final Product product = (Product) o; + return Objects.equals(price, product.price) && Objects.equals(name, product.name); + } + + @Override + public int hashCode() { + return Objects.hash(price, name); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/exception/DomainException.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/exception/DomainException.java new file mode 100644 index 0000000000..05d25cc800 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/exception/DomainException.java @@ -0,0 +1,7 @@ +package com.baeldung.ddd.layers.domain.exception; + +public class DomainException extends RuntimeException { + public DomainException(final String message) { + super(message); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/repository/OrderRepository.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/repository/OrderRepository.java new file mode 100644 index 0000000000..45b0c42782 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/repository/OrderRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.ddd.layers.domain.repository; + +import com.baeldung.ddd.layers.domain.Order; +import org.bson.types.ObjectId; + +import java.util.Optional; + +public interface OrderRepository { + Optional findById(ObjectId id); + + void save(Order order); +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/service/DomainOrderService.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/service/DomainOrderService.java new file mode 100644 index 0000000000..961309e94e --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/service/DomainOrderService.java @@ -0,0 +1,56 @@ +package com.baeldung.ddd.layers.domain.service; + +import com.baeldung.ddd.layers.domain.Order; +import com.baeldung.ddd.layers.domain.Product; +import com.baeldung.ddd.layers.domain.exception.DomainException; +import com.baeldung.ddd.layers.domain.repository.OrderRepository; +import org.bson.types.ObjectId; + +import java.util.List; + +public class DomainOrderService implements OrderService { + + private final OrderRepository orderRepository; + + public DomainOrderService(OrderRepository orderRepository) { + this.orderRepository = orderRepository; + } + + @Override + public ObjectId createOrder(List products) { + final Order order = new Order(ObjectId.get(), products); + orderRepository.save(order); + + return order.getId(); + } + + @Override + public void addProduct(ObjectId id, Product product) { + final Order order = getOrder(id); + order.addProduct(product); + + orderRepository.save(order); + } + + @Override + public void completeOrder(ObjectId id) { + final Order order = getOrder(id); + order.complete(); + + orderRepository.save(order); + } + + @Override + public void deleteProduct(ObjectId id, String name) { + final Order order = getOrder(id); + order.removeProduct(name); + + orderRepository.save(order); + } + + private Order getOrder(ObjectId id) { + return orderRepository + .findById(id) + .orElseThrow(() -> new RuntimeException("Order with given id doesn't exist")); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/domain/service/OrderService.java b/ddd/src/main/java/com/baeldung/ddd/layers/domain/service/OrderService.java new file mode 100644 index 0000000000..dbc7d3aba1 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/domain/service/OrderService.java @@ -0,0 +1,16 @@ +package com.baeldung.ddd.layers.domain.service; + +import com.baeldung.ddd.layers.domain.Product; +import org.bson.types.ObjectId; + +import java.util.List; + +public interface OrderService { + ObjectId createOrder(List products); + + void addProduct(ObjectId id, Product product); + + void completeOrder(ObjectId id); + + void deleteProduct(ObjectId id, String name); +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/DomainConfiguration.java b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/DomainConfiguration.java new file mode 100644 index 0000000000..7c56456719 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/DomainConfiguration.java @@ -0,0 +1,16 @@ +package com.baeldung.ddd.layers.infrastracture.configuration; + +import com.baeldung.ddd.layers.domain.repository.OrderRepository; +import com.baeldung.ddd.layers.domain.service.DomainOrderService; +import com.baeldung.ddd.layers.domain.service.OrderService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class DomainConfiguration { + + @Bean + OrderService orderService(final OrderRepository orderRepository) { + return new DomainOrderService(orderRepository); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/MongoDBConfiguration.java b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/MongoDBConfiguration.java new file mode 100644 index 0000000000..db6743e90f --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/configuration/MongoDBConfiguration.java @@ -0,0 +1,7 @@ +package com.baeldung.ddd.layers.infrastracture.configuration; + +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@EnableMongoRepositories +public class MongoDBConfiguration { +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepository.java b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepository.java new file mode 100644 index 0000000000..5ec166738a --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepository.java @@ -0,0 +1,30 @@ +package com.baeldung.ddd.layers.infrastracture.repository; + +import com.baeldung.ddd.layers.domain.Order; +import com.baeldung.ddd.layers.domain.repository.OrderRepository; +import org.bson.types.ObjectId; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class MongoDbOrderRepository implements OrderRepository { + + private final SpringDataOrderRepository orderRepository; + + @Autowired + public MongoDbOrderRepository(final SpringDataOrderRepository orderRepository) { + this.orderRepository = orderRepository; + } + + @Override + public Optional findById(final ObjectId id) { + return orderRepository.findById(id); + } + + @Override + public void save(final Order order) { + orderRepository.save(order); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/SpringDataOrderRepository.java b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/SpringDataOrderRepository.java new file mode 100644 index 0000000000..0cbbcb3827 --- /dev/null +++ b/ddd/src/main/java/com/baeldung/ddd/layers/infrastracture/repository/SpringDataOrderRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.ddd.layers.infrastracture.repository; + +import com.baeldung.ddd.layers.domain.Order; +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SpringDataOrderRepository extends MongoRepository { +} diff --git a/ddd/src/main/resources/ddd-layers.properties b/ddd/src/main/resources/ddd-layers.properties new file mode 100644 index 0000000000..0479996b17 --- /dev/null +++ b/ddd/src/main/resources/ddd-layers.properties @@ -0,0 +1,5 @@ +spring.data.mongodb.host=localhost +spring.data.mongodb.port=27017 +spring.data.mongodb.database=order-database +spring.data.mongodb.username=order +spring.data.mongodb.password=order \ No newline at end of file diff --git a/ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderProvider.java b/ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderProvider.java new file mode 100644 index 0000000000..8aa3ff4068 --- /dev/null +++ b/ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderProvider.java @@ -0,0 +1,19 @@ +package com.baeldung.ddd.layers.domain; + +import org.bson.types.ObjectId; + +import java.math.BigDecimal; +import java.util.Arrays; + +public class OrderProvider { + public static Order getCreatedOrder() { + return new Order(ObjectId.get(), Arrays.asList(new Product(BigDecimal.TEN, "productName"))); + } + + public static Order getCompletedOrder() { + final Order order = getCreatedOrder(); + order.complete(); + + return order; + } +} diff --git a/ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderUnitTest.java b/ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderUnitTest.java new file mode 100644 index 0000000000..0996383610 --- /dev/null +++ b/ddd/src/test/java/com/baeldung/ddd/layers/domain/OrderUnitTest.java @@ -0,0 +1,57 @@ +package com.baeldung.ddd.layers.domain; + +import com.baeldung.ddd.layers.domain.exception.DomainException; +import org.bson.types.ObjectId; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import java.math.BigDecimal; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class OrderUnitTest { + + @Test + void shouldCompleteOrder_thenChangeStatus() { + final Order order = OrderProvider.getCreatedOrder(); + + order.complete(); + + assertEquals(OrderStatus.COMPLETED, order.getStatus()); + } + + @Test + void shouldAddProduct_thenUpdatePrice() { + final Order order = OrderProvider.getCreatedOrder(); + final int orderOriginalProductSize = order.getProducts().size(); + final BigDecimal orderOriginalPrice = order.getPrice(); + final Product productToAdd = new Product(new BigDecimal("20"), "secondProduct"); + + order.addProduct(productToAdd); + + assertEquals(orderOriginalProductSize + 1, order.getProducts().size()); + assertEquals(orderOriginalPrice.add(productToAdd.getPrice()), order.getPrice()); + } + + @Test + void shouldAddProduct_thenThrowException(){ + final Order order = OrderProvider.getCompletedOrder(); + final Product productToAdd = new Product(new BigDecimal("20"), "secondProduct"); + + final Executable executable = () -> order.addProduct(productToAdd); + + Assertions.assertThrows(DomainException.class, executable); + } + + @Test + void shouldRemoveProduct_thenUpdatePrice() { + final Order order = OrderProvider.getCreatedOrder(); + + order.removeProduct(order.getProducts().get(0).getName()); + + assertEquals(0, order.getProducts().size()); + assertEquals(BigDecimal.ZERO, order.getPrice()); + } +} \ No newline at end of file diff --git a/ddd/src/test/java/com/baeldung/ddd/layers/domain/service/DomainOrderServiceUnitTest.java b/ddd/src/test/java/com/baeldung/ddd/layers/domain/service/DomainOrderServiceUnitTest.java new file mode 100644 index 0000000000..841f49f7f5 --- /dev/null +++ b/ddd/src/test/java/com/baeldung/ddd/layers/domain/service/DomainOrderServiceUnitTest.java @@ -0,0 +1,91 @@ +package com.baeldung.ddd.layers.domain.service; + +import com.baeldung.ddd.layers.domain.Order; +import com.baeldung.ddd.layers.domain.OrderProvider; +import com.baeldung.ddd.layers.domain.Product; +import com.baeldung.ddd.layers.domain.repository.OrderRepository; +import org.bson.types.ObjectId; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +class DomainOrderServiceUnitTest { + + private OrderRepository orderRepository; + private DomainOrderService tested; + + @BeforeEach + void setUp() { + orderRepository = mock(OrderRepository.class); + tested = new DomainOrderService(orderRepository); + } + + @Test + void shouldCreateOrder_thenSaveIt() { + final Product product = new Product(BigDecimal.TEN, "productName"); + + final ObjectId id = tested.createOrder(Arrays.asList(product)); + + verify(orderRepository).save(any(Order.class)); + assertNotNull(id); + } + + @Test + void shouldAddProduct_thenSaveOrder() { + final Order order = spy(OrderProvider.getCreatedOrder()); + final Product product = new Product(BigDecimal.TEN, "test"); + when(orderRepository.findById(order.getId())).thenReturn(Optional.of(order)); + + tested.addProduct(order.getId(), product); + + verify(orderRepository).save(order); + verify(order).addProduct(product); + } + + @Test + void shouldAddProduct_thenThrowException() { + final Product product = new Product(BigDecimal.TEN, "test"); + final ObjectId id = ObjectId.get(); + when(orderRepository.findById(id)).thenReturn(Optional.empty()); + + final Executable executable = () -> tested.addProduct(id, product); + + verify(orderRepository, times(0)).save(any(Order.class)); + assertThrows(RuntimeException.class, executable); + } + + @Test + void shouldCompleteOrder_thenSaveIt() { + final Order order = spy(OrderProvider.getCreatedOrder()); + when(orderRepository.findById(order.getId())).thenReturn(Optional.of(order)); + + tested.completeOrder(order.getId()); + + verify(orderRepository).save(any(Order.class)); + verify(order).complete(); + } + + @Test + void shouldDeleteProduct_thenSaveOrder() { + final Order order = spy(OrderProvider.getCreatedOrder()); + final String productName = order + .getProducts() + .get(0) + .getName(); + when(orderRepository.findById(order.getId())).thenReturn(Optional.of(order)); + + tested.deleteProduct(order.getId(), productName); + + verify(orderRepository).save(order); + verify(order).removeProduct(productName); + } +} \ No newline at end of file diff --git a/ddd/src/test/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java b/ddd/src/test/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java new file mode 100644 index 0000000000..356e60946c --- /dev/null +++ b/ddd/src/test/java/com/baeldung/ddd/layers/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java @@ -0,0 +1,25 @@ +package com.baeldung.ddd.layers.infrastracture.repository; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class MongoDbOrderRepositoryUnitTest { + + private SpringDataOrderRepository springDataOrderRepository; + private MongoDbOrderRepository tested; + + @BeforeEach + void setUp(){ + + } + + @Test + void findById() { + } + + @Test + void save() { + } +} \ No newline at end of file