ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [스프링부트/웹 애플리케이션 개발]주문 도메인 개발-2
    스프링&스프링부트 2023. 1. 5. 13:13

    주문 기능 테스트

    package jpabook.jpashop.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.item.Book;
    import jpabook.jpashop.domain.item.Item;
    import jpabook.jpashop.exception.NotEnoughStockException;
    import jpabook.jpashop.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.*;
    import static org.junit.Assert.assertEquals;
    
    @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 = new Member();
            //member.setName("회원1");
            //member.setAddress(new Address("서울", "강가", "123-123"));
            //em.persist(member);
            //반복적으로 사용하니까 extract Method
    
            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하는 것 중요함
        //remove의 별도 단위테스트있는게 좋음
        @Test(expected = NotEnoughStockException.class)
        public void 상품주문_재고수량초과()throws Exception {
            //given
            Member member = createMember();
            Item item = createBook("JPA책", 10000, 10);
    
            int orderCount = 11;
    
            //when
            orderService.order(member.getId(), item.getId(), orderCount);
    
            //then
            fail("재고 수량 부족 예외가 발생해야한다.");
        }
    
        @Test
        public void 주문취소()throws Exception {
            //given
            Member member = createMember();
            Book item = createBook("JPA책", 10000, 10);
    
            int orderCount = 2;
    
            Long orderId = orderService.order(member.getId(), item.getId(), orderCount);
    
            //when
            orderService.cancelOrder(orderId);
    
            //then
            Order getOrder = orderRepository.findOne(orderId);
    
            assertEquals("주문 취소시 상태는 CANCEL이다.", OrderStatus.CANCEL, getOrder.getStatus());
            assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, item.getStockQuantity());
        }
    
        private Book createBook(String name, int price, int stockQuantity) {
            Book book = new Book();
            book.setName(name);
            book.setPrice(price);
            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;
        }
    
        //정말 좋은 테스트 > 단위 테스트 의미있게
    
    }

     

     

     

    주문 검색 기능

    - JPA에서 동적쿼리 해결?

    방법1. JPQL 사용, 실무에서 사용하지 않음

    public List<Order> findAllByString(OrderSearch orderSearch) {
    	//language=JPAQL
    	String jpql = "select o From Order o join o.member m";
    	boolean isFirstCondition = true;
    
    	//주문 상태 검색
    	if (orderSearch.getOrderStatus() != null) {
    		if (isFirstCondition) {
    			jpql += " where";
    			isFirstCondition = false;
    		} else {
    			jpql += " and";
    		}
    	jpql += " o.status = :status";
    	}
        
    	//회원 이름 검색
    	if (StringUtils.hasText(orderSearch.getMemberName())) {
    		if (isFirstCondition) {
    			jpql += " where";
    			isFirstCondition = false;
    		} else {
    			jpql += " and";
    		}
    		jpql += " m.name like :name";
    	}
        
    	TypedQuery<Order> query = em.createQuery(jpql, Order.class)
    	.setMaxResults(1000); //최대 1000건
    	if (orderSearch.getOrderStatus() != null) {
    		query = query.setParameter("status", orderSearch.getOrderStatus());
    	}
    	if (StringUtils.hasText(orderSearch.getMemberName())) {
    		query = query.setParameter("name", orderSearch.getMemberName());
    	}
    	return query.getResultList();
    }

    - mybatis 사용 이유 > 동적 쿼리에서 편리함

     

    방법2. JPA Criteria > 실무에서 사용하지 않음, 유지보수 불가능

    public List<Order> findAllByCriteria(OrderSearch orderSearch) {
         CriteriaBuilder cb = em.getCriteriaBuilder();
         CriteriaQuery<Order> cq = cb.createQuery(Order.class);
         Root<Order> o = cq.from(Order.class);
         Join<Order, Member> m = o.join("member", JoinType.INNER); //회원과 조인
         List<Predicate> criteria = new ArrayList<>();
         
         //주문 상태 검색
         if (orderSearch.getOrderStatus() != null) {
             Predicate status = cb.equal(o.get("status"),
    		orderSearch.getOrderStatus());
             criteria.add(status);
         }
         
         //회원 이름 검색
         if (StringUtils.hasText(orderSearch.getMemberName())) {
         Predicate name =
         cb.like(m.<String>get("name"), "%" +
         orderSearch.getMemberName() + "%");
         criteria.add(name);
         }
         
    	cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
    	TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 1000건
    	return query.getResultList();
    }

     

    방법3. . Querydsl 

     

    728x90
Designed by Tistory.