package jpabook.jpashop.domain.service;
import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderStatus;
import jpabook.jpashop.domain.exception.NotEnoughStockException;
import jpabook.jpashop.domain.item.Book;
import jpabook.jpashop.domain.repository.OrderRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class OrderServiceTest {
@Autowired EntityManager em;
@Autowired OrderService orderService;
@Autowired OrderRepository orderRepository;
@Test
public void 상품주문() throws Exception {
//given
Member member = createMember();
Book book = createBook("시골 JPA", 10000, 10);
int orderCount = 2;
//when
Long orderId = orderService.order(member.getId(), book.getId(), orderCount);
//then
Order getOrder = orderRepository.findOne(orderId);
assertEquals("상품 주문 시 상태는 ORDER", OrderStatus.ORDER, getOrder.getStatus());
assertEquals("주문한 상품 종류 수가 정확해야 한다", 1, getOrder.getOrderItems().size());
assertEquals("주문 가격은 가격 * 수량이다.", 10000 * orderCount, getOrder.getTotalPrice());
assertEquals("주문 수량 만큼 재고가 줄어야 한다", 8, book.getStockQuantity());
}
@Test
public void 주문취소() throws Exception {
//given
Member member = createMember();
Book book = createBook("시골 JPA", 10000, 10);
int orderCount = 2;
Long orderId = orderService.order(member.getId(), book.getId(), orderCount);
//when
orderService.cancelOrder(orderId);
//then
Order getOrder = orderRepository.findOne(orderId);
assertEquals("주문 취소 시 상태는 CANCEL 이다", OrderStatus.CANCEL, getOrder.getStatus());
assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, book.getStockQuantity());
}
@Test(expected = NotEnoughStockException.class)
public void 상품주문_재고수량초과() throws Exception {
//given
Member member = createMember();
Book book = createBook("시골 JPA", 10000, 10);
int orderCount = 11;
//when
orderService.order(member.getId(), book.getId(), orderCount);
//then
fail("재고 수량 부족 예외가 발생해야 한다.");
}
private Book createBook(String name, int orderPrice, int stockQuantity) {
Book book = new Book();
book.setName(name);
book.setPrice(orderPrice);
book.setStockQuantity(stockQuantity);
em.persist(book);
return book;
}
private Member createMember() {
Member member = new Member();
member.setName("회원1");
member.setAddress(new Address("서울", "강가", "123-123"));
em.persist(member);
return member;
}
}
상품 주문이 정상 동작하는지 확인하는 테스트다. Given 절에서 테스트를 위한 회원과 상품을 만들고 When 절에서 실제 상품을 주문하고 Then 절에서 주문 가격이 올바른지, 주문 후 재고 수량이 정확히 줄었는지 검증한다.
@Test(expected = NotEnoughStockException.class)
public void 상품주문_재고수량초과() throws Exception {
//given
Member member = createMember();
Book book = createBook("시골 JPA", 10000, 10);
int orderCount = 11;
//when
orderService.order(member.getId(), book.getId(), orderCount);
//then
fail("재고 수량 부족 예외가 발생해야 한다.");
}
재고는 10으로 설정하고 주문 수량을 11로 설정할 경우 Item 엔티티에 설정한 예외가 발생한다.
public void removeStock(int quantity){
int restStock = this.stockQuantity - quantity;
if (restStock < 0) {
throw new NotEnoughStockException("need more stock");
}
this.stockQuantity = restStock;
}
이 예외는 Exception 클래스에 다음과 같이 정의되어있다.
package jpabook.jpashop.domain.exception;
public class NotEnoughStockException extends RuntimeException{
public NotEnoughStockException() {
super();
}
public NotEnoughStockException(String message) {
super(message);
}
public NotEnoughStockException(String message, Throwable cause) {
super(message, cause);
}
public NotEnoughStockException(Throwable cause) {
super(cause);
}
}
@Test
public void 주문취소() throws Exception {
//given
Member member = createMember();
Book book = createBook("시골 JPA", 10000, 10);
int orderCount = 2;
Long orderId = orderService.order(member.getId(), book.getId(), orderCount);
//when
orderService.cancelOrder(orderId);
//then
Order getOrder = orderRepository.findOne(orderId);
assertEquals("주문 취소 시 상태는 CANCEL 이다", OrderStatus.CANCEL, getOrder.getStatus());
assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, book.getStockQuantity());
}
주문을 취소하려면 먼저 주문을 해야 한다. 따라서 Given절에서 주문을 하고 When절에서 해당 주문을 취소했다. Then절에서 주문 상태가 주문 취소 상태인지(CANCEL), 취소한 만큼 재고가 증가했는지 검증한다.
private Book createBook(String name, int orderPrice, int stockQuantity) {
Book book = new Book();
book.setName(name);
book.setPrice(orderPrice);
book.setStockQuantity(stockQuantity);
em.persist(book);
return book;
}
private Member createMember() {
Member member = new Member();
member.setName("회원1");
member.setAddress(new Address("서울", "강가", "123-123"));
em.persist(member);
return member;
}
각 테스트케이스마다 회원정보와 상품정보가 필요하다. 실제로 우리가 알아보고자 하는 것은 OrderService의 기능이 정상적으로 동작하는가 뿐인데 해당 기능은 회원정보와 상품 정보에 의존하기 때문에 불가피하게 정보가 필요하다.