Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- 깃 터미널 연동
- 모두의 네트워크
- 정리
- HTTP
- 스터디
- React Native
- 네트워크
- 깃허브 토큰 인증
- 깃 연동
- 백준 4358 자바
- 백준 4949번
- 문자열
- 리액트 네이티브 시작하기
- 자바
- 팀플회고
- 백준
- 지네릭스
- 딥러닝
- 모두를위한딥러닝
- 백준 4358번
- 리액트 네이티브
- 리액트 네이티브 프로젝트 생성
- 모두를 위한 딥러닝
- 머신러닝
- 깃허브 로그인
- 백준 5525번
- SQL
- 데이터베이스
- 데베
- 모두의네트워크
Archives
- Today
- Total
솜이의 데브로그
[Spring Boot] 주문 도메인 개발(2) 본문
Reference : Inflearn 실전 스프링부트와 JPA 활용 (김영한님 강의)
주문 기능 테스트
- 상품 주문 성공
- 상품 주문 시 재고수량을 초과하면 안된다
- 주문 취소가 성공해야함
위의 조건들을 만족하는지 테스트해보자.
OrderServiceTest.java
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.exceptioin.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.aspectj.bridge.MessageUtil.fail;
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 = 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 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());
}
@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("재고 수량 부족 예외가 발생해야 한다.");
}
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;
}
}
Assert는 인수를 검증하고 조건에 맞지 않는지 확인
→ assertEquals, fail 등
주문 초과하는 수량으로 테스트해보면 로직에서 예외가 발생.
order entity에 대해서 비즈니스 로직을 작성해버리는 것도 가능.
단위 테스트로 작성하는 것이 중요.
주문 검색 기능 개발
JPA에서 동적 쿼리를 어떻게 해결해야 하는가?
repository/OrderSearch.java
package jpabook.jpashop.repository;
import jpabook.jpashop.domain.OrderStatus;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class OrderSearch {
private String memberName; //회원 이름
private OrderStatus orderStatus; //주문 상태[ORDER, CANCEL]
}
repository/OrderRepository.java
동적 쿼리 생성
findAll 함수 작성시 세가지 방법
(1) JPQL로 처리
(생략..) 안씀
(2) JPA Criteria로 처리
/**
* 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<Object, Object> 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);
return query.getResultList();
}
이것도 잘 안씀. 실무에서 사용하기에 너무 복잡하다.
(3) Querydsl 로 처리
public List<Order> findAll(OrderSearch orderSearch){
QOrder order = QOrder.order;
QMember member = QMember.member;
return query
.select(order)
.from(order)
.join(order.member, member)
.where(statusEq(orderSearch.getOrderStatus()),
nameLike(orderSearch.getMemberName()))
.limit(1000)
.fetch();
}
privte BooleanExpression statusEq(OrderStatus statusCond) {
if(statusCond == null) {
return null;
}
return order.status.eq(statusCond);
}
private BooleanExpression nameLike(String nameCond) {
if(!StringUtils.hasText(nameCond)) {
return null;
}
return member.name.like(nameCond);
}
실무에서는 Spring Boot, Springdata JPA, querydsl 을 잘 알아둬야한다~~
더 공부해봐야할것
@Autowired 어노테이션
EntityManager 사용법.. em.persist 해서 어디에 넣어주는건데..
→ Entity 내부에 영속성 컨텍스트 (Persistence Context) 를 두어서 엔티티를 관리하는 것!! 즉, 비휘발성으로 관리하여 엔티티를 영구적으로 저장하는 환경.
ㅋㅋㅋ 공부를 하면 할수록 모르는게 이렇게나 많고.. 공부해야할건 더욱 더 많다는것을 느낀다. 눈물..
'dev > Spring Boot' 카테고리의 다른 글
[Spring Boot] 웹 계층 개발(2) (0) | 2022.03.31 |
---|---|
[SpringBoot] 웹 계층 개발(1) (0) | 2022.03.25 |
[Spring Boot] 주문 도메인 개발(1) (0) | 2021.11.17 |
[Spring Boot] 상품 도메인 개발 (0) | 2021.11.15 |
[Spring Boot] 회원 도메인 개발 (0) | 2021.11.10 |