JAVA SPRING/PROJECT

[Day-10] 주문기능테스트, 부트스트랩적용

sshhhh 2023. 8. 25.

#주문기능테스트

 

테스트 요구사항

- 상품 주문이 성공해야 한다.

- 상품을 주문할 때 재고 수량을 초과하면 안 된다.

- 주문 취소가 성공해야 한다.

 

OrderServiceTest

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class OrderServiceTest {

    @Autowired
    EntityManager em;
    @Autowired
    OrderService 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(x, y,z)  객체 x와 y가 일치함을 확인 z :실제값
        assertEquals("상품 주문시 상태는 ORDER", OrderStatus.ORDER, getOrder.getStatus());
        assertEquals("주문한 상품 종류 수가 정확해야 한다.", 1, getOrder.getOrderItems().size());
        assertEquals("주문 가격은 가격 * 수량이다.",10000 * orderCount,getOrder.getTotalPrice());
        assertEquals("주문 수량만큼 재고가 줄어야 한다.",8, book.getStockQuantity());


    }



    @Test(expected = NotEnoughStockException.class) //재고수량 초과되면 예외가 터져야함
    public void 상품주문_재고수량초과() throws Exception {
        //given
        Member member= createMember();
        Item item = createBook("시골",10000,10); //재고 10개인데

        int orderCount =11; //11개 주문하면

        //when
        Long orderId = orderService.order(member.getId(), item.getId(), orderCount); //잘못된거니까 예외터져야

        //then
        fail("재고 수량 부족 예외가 발생해야 하는데 여기로 오면 잘못된 코드다");
    }

   @Test
    public void 주문취소() throws Exception {
       //given : 이런게 주어짐
       Member member= createMember();
       Book item = createBook("시골",10000,10); //10개에서
       int orderCount =2; //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); //ctrl alt p
        em.persist(book);
        return book;
    }

    private Member createMember() {
        Member member = new Member();
        member.setName("회원1");
        member.setAddress(new Address("서울", "강가", "123"));
        em.persist(member);
        return member;
    }
    

}

 

 

 

OrderRepository

@Repository
@RequiredArgsConstructor
public class OrderRepository {

    private final EntityManager em;

    public void save(Order order) {
        em.persist(order);
    }

    //단건 조회
    public Order findOne(Long id) {

        return em.find(Order.class, id);
    }

 

 

동적쿼리 jpql로 작성시 오류발생확률 높고... 실무에서 안씀!!

//주문내역 검색 
    public List<Order> findAll(OrderSearch orderSearch) {


        String jpql = "select o from Order o join o.member m";  //order를 조회하고 order랑 order랑 연관된 member를 join한다.

        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();
    }

}

 

 

JPA가 제공하는 표준 동적쿼리 (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();
}

 

 

-> Querydsl 사용할 것 

 

<웹 계층 개발>

 

파일 구조


 

 

HomeController

@Controller
@Slf4j //logger(lombok)
public class HomeController {
    
    @RequestMapping("/")
    public String home(){
        log.info("home controller");
        return "home"; //home.html 찾아간다.
    }
}

 


 

 

#Thymeleaf layout

https://www.thymeleaf.org/doc/articles/layouts.html

 

Thymeleaf Page Layouts - Thymeleaf

Summary In this article, we described many ways of achieving the same: layouts. You can build layouts using Thymeleaf Standard Layout System that is based on include-style approach. You also have powerful Layout Dialect, that uses decorator pattern for wor

www.thymeleaf.org

 

 

#부트스트랩 적용

 

다운

https://getbootstrap.com/

 

Bootstrap

The most popular HTML, CSS, and JS library in the world.

getbootstrap.com

 

home.html 일부

<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header">  <!--include header 느낌
                                                   fragments/header의 위치에 header 라는 파일이 있다 -->

 

header.html 일부 

<head th:fragment="header"><!--이거를 home으로-->

 

부트 스트랩 복사 붙여넣기 후

 

http://localhost:8080/

 

 

 

강의 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-%ED%99%9C%EC%9A%A9-1/dashboard

댓글