주문 서비스
주문 서비스에서는 주문 조회와 주문하기와 주문 취소하기 기능이 있다.
public interface OrderService {
List<OrderDto> getOrders(long memberId);
OrderDto getOrder(long orderId);
void placeOrder(OrderRequest orderRequest);
void cancelOrder(long orderId);
}
하나의 서비스에서 너무 많은 기능을 하거나 복잡해 진다면 기능 단위로 분리하자
/** 주문 조회 서비스 */
public interface OrderQueryService {
List<OrderDto> getOrders(long memberId);
OrderDto getOrder(long orderId);
}
/** 주문 처리 서비스 */
public interface OrderCommandService {
void placeOrder(OrderRequest orderRequest);
void cancelOrder(long orderId);
}
주문하기
주문정보를 가지고 주문하기를 실행하면 주문 객체가 생성(저장)된다.
이렇게 동작하도록 테스트를 작성해보자.
public class OrderCommandServiceTest {
private final OrderCommandService orderCommandService;
private final OrderRepository orderRepository;
public OrderCommandServiceTest() {
orderRepository = mock(OrderRepository.class);
orderCommandService = new OrderCommandService(orderRepository);
}
/**
* 테스트 예시
*/
@Test
public void createOrderSuccessTest() {
// given (테스트를 위한 준비)
final long orderId;
OrderRequest orderRequest = new OrderRequset(orderId);
// when (테스트 하련느 행동 실행)
orderCommandService.placeOrder(orderRequest);
// then (실행 결과 예상 값 비교)
ArgumentCaptor<Order> orderCaptor = ArgumentCaptor.forClass(Order.class);
verify(orderRepository).save(orderCaptor.capture());
final Order order = orderCaptor.getValue();
assertThat(order, notNullValue());
assertThat(getField(order, "ordererId"), is(ordererId));
}
}
given-when-then 패턴
BDD(Behavior-Driven Development) 중 하나로 아래와 같은 구조를 가진다.
given : 테스트를 위한 준비 (테스트를 위한 상태 설정)
when : 테스트 하려는 행동
then : 실행한 결과의 예상되는 변화 설명
Mapper
OrderCommandService 의 Order 메소드에서 해야 할 일은 아래와 같다.
입력된 정보(OrderRequest)로 주문(Order)를 생성하여 저장한다.
이때 OrderRequest -> Order 변환은 단순 변환하는 작업이지만 코드 양이 많고 OrderCommandService 와 클래스를 분리 할 수 있다.
이렇게 dto -> domain 을 변환해 주는 것을 Mapper 라고 하자.
orderMapper
public interface OrderMapper {
Order mapFrom(OrderRequest orderRequest);
}
OrderMapper 의 기능으로 테스트 코드를 작성하자.
public class OrderMapperTest {
private final OrderMapper orderMapper = new OrderMapper();
@Test
public void orderMapperTest() {
// given
final long ordererId = 1;
// ...
// when
Order order = orderMapper.mapFrom(orderer, orderRequest);
// then
assertThat(order, notNullValue());
assertThat(getField(order, "ordererId"), is(ordererId));
// ...
}
}
orderValidator
주문을 하기 전에 주문이 가능한지 검증이 필요하다.
주문 금액이 맞는지 주문이 가능한지 등의 여부를 확인해야하는데 OrderValidator 라는 것을 만들어서 이러한 역활을 여기서 처리한다.
public class OrderValidator {
void validate(Order order);
}
역활에 따라 기능들을 분리하여 가독성이 좋아진 모습을 볼 수 있다.
public class OrderCommandService {
private final OderMapper orderMapper;
private final OrderValidator orderValidator;
private final OrderRepository orderRepository;
public OrderCommandService(OrderMapper orderMapper, OrderValidator orderValidator, OrderRepository orderRepository) {
this.orderMapper = orderMapper;
this.orderValidator = orderValidator;
this.orderRepository = orderRepository;
}
public void placeOrder(OrderRequest orderRequest) {
Order order = orderMapper.mapFrom(orderRequest);
order.place(orderValidator);
orderRepository.save();
}
}