먼저 Inner Class 를 사용하여 1개의 Class 파일에서 상품을 등록하는 기능을 구현한다.
소스는 아래와 같다.
아래의 소스는 다음의 순서를 가진다.
- ProductService에 addProduct 라는 요청을 보낸다.
- ProductService에서는 Product를 생성하여, ProductPort에게 save 할 것을 명령한다.
- ProductPort의 구현체인 ProductAdapter에서 Memory나 DB로 저장을 한다.
package com.example.productorderservice.product;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
class ProductServiceTest {
private ProductService productService;
private ProductPort productPort;
private ProductRepository productRepository;
@BeforeEach
void setUp(){
productRepository = new ProductRepository();
productPort = new ProductAdapter(productRepository);
productService = new ProductService(productPort);
}
@Test
void 상품등록() {
final String name ="상품명";
final int price = 1000;
final DiscountPolicy discountPolicy = DiscountPolicy.NONE;
final AddProductRequest request = new AddProductRequest(name, price, discountPolicy);
productService.addProduct(request);
}
private record AddProductRequest(String name, int price,
DiscountPolicy discountPolicy) {
private AddProductRequest {
Assert.hasText(name, "상품명은 필수입니다.");
Assert.isTrue(price > 0, "상품 가격은 0보다 커야 합니다.");
Assert.notNull(discountPolicy, "할인 정책은 필수입니다.");
}
}
private enum DiscountPolicy{
NONE
}
private class ProductService {
private final ProductPort productPort;
private ProductService(ProductPort productPort) {
this.productPort = productPort;
}
public void addProduct(final AddProductRequest request) {
final Product product = new Product(request.name(), request.price(), request.discountPolicy());
productPort.save(product);
}
}
private class Product {
private Long id;
private final String name;
private final int price;
private final DiscountPolicy discountPolicy;
public Product(final String name, int price, DiscountPolicy discountPolicy) {
Assert.hasText(name,"상품명은 필수입니다.");
Assert.isTrue(price>0, "상품 가격은 0보다 커야 합니다.");
Assert.notNull(discountPolicy,"할인 정책은 필수입니다.");
this.name = name;
this.price = price;
this.discountPolicy = discountPolicy;
}
public void assignId(final Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}
private interface ProductPort {
void save(final Product product);
}
private class ProductAdapter implements ProductPort {
private final ProductRepository productRepository;
private ProductAdapter(final ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Override
public void save(final Product product){
productRepository.save(product);
}
}
private class ProductRepository {
private Long sequence = 0L;
private Map<Long, Product> persistence = new HashMap<>();
public void save(final Product product){
product.assignId(++sequence);
persistence.put(product.getId(),product);
}
}
}
실행결과
기능이 정상적으로 동작하는 것을 확인하면 Inner Class 로 선언되어 있는 것들을 한단계 상위로 빼준다.
현재의 디렉토리 구조
Inner Class를 상위로 빼준 후 디렉토리 구조
소스는 아래 Git 참고 https://github.com/ShinHenry/product-order-service.git
출처 : 실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
'Backend > TDD' 카테고리의 다른 글
[TDD] JPA 적용하기 (0) | 2023.02.16 |
---|---|
[TDD] API 테스트로 전환하기 (0) | 2023.02.15 |
[TDD] POJO를 스프링부트 테스트로 전환하기 (0) | 2023.02.15 |
[TDD] TDD 구현 실습 - 프로젝트 소개 및 생성 (0) | 2023.02.14 |
TDD(Test-Driven-Development) 방법론 (0) | 2023.02.14 |