우아한테크코스 6기 백엔드 프리코스 - 크리스마스 프로모션

테스트 목록

미션 완성을 위해 통과해야 하는 테스트 목록(줄이 쳐진 항목은 이미 통과)

비즈니스 로직
m4t01 - 크리스마스 디데이(12.1~12.25) 할인 금액 계산
m4t02 - 12월 평일(일~목) 할인 : 디저트 메뉴 1개당 2,023원 할인
m4t03 - 12월 주말(금,토) 할인 : 메인 메뉴 1개당 2,023원 할인
m4t04 - 12월 특별할인(⭐️) : 총주문 금액에서 1,000원 할인
m4t05 - 12월 증정 이벤트 : 총주문 금액이 12만원 이상인 경우 샴페인 1개 증정
m4t06 - 총혜택 금액 계산
m4t07 - 총혜택 금액에 따른 배지 부여
개발 요청 사항
m4t08 - 식당 방문 예상 날짜는 1이상 31이하의 숫자만 가능 (이외의 경우 예외를 던진다)
m4t09 - 메뉴 주문 입력 유효성 검사 (유효하지 않은 상품 입력에 대해 예외를 던진다)
m4t10 - 메뉴 주문 입력 유효성 검사 (유효하지 않은 수량 입력에 대해 예외를 던진다)
m4t11 - 메뉴 주문 유효성 검사 (음료만 주문한 경우 예외를 던진다)
m4t12 - 메뉴 주문 유효성 검사 (중복된 상품을 주문한 경우 예외를 던진다)

저번 과제가 끝나고 다른 사람들의 코드를 리뷰하다가 @ParametrizedTest 라는 기능을 알게 되었다. 이번 미션에는 @ParametrizedTest를 사용해서 테스트 코드를 간결하게 작성하려고 노력했다.

feedback-test-code

그동안 테스트 코드에 대해서는 테스트 코드의 목적만을 중요하게 생각하고 그 과정은 중요하게 생각하지 않았다.

m4t09

@ParametrizedTest를 사용하여 반복문 없이 직관적으로 의도를 파악할 수 있도록 코드를 작성할 수 있었다.

m4t09

오류가 많아서 수정했다.
주문 상품의 존재여부수량에 대한 검증을 한 번에 테스트하려고 했지만 이 두 로직은 독립적인 서비스 정책이기도 하고 구현 클래스의 역할을 명확하게 구분하기 위해 테스트를 분리했다.

m4t09-수정

m4t10

주문한 상품들의 수량의 총합은 20을 넘을 수 없고 각 상품은 1개 이상 주문해야 한다. 그렇지 않은 경우 예외가 발생한다.

m4t10

@CsvSource 어노테이션을 @ValueSource 어노테이션으로 바꿨다.

m4t10-1

@ValueSource vs @CsvSource

저번 주차 코드리뷰에서 본 @CsvSource 어노테이션을 무심코 따라 사용했다가 3주차 공통 피드백 문서에서 사용된 @ValueSource로 수정했다. 이 둘의 차이는 뭘까?

parameterized-test

CSV는 Comman-Seperated Value의 약자다. 몇 가지 필드를 쉼표로 구분하는 데이터 양식이다.

m4t11

음료만 주문할 수는 없다. 서비스 정책이므로 검증의 책임은 도메인 클래스OrderBasket에 있다.

m4t11

m4t12

“해산물파스타-1,제로콜라-2,해산물파스타-1”과 같이 동일한 상품을 여러 번 주문한 경우 예외 발생. 도메인(서비스 정책)과는 관련이 없으므로 IO 레벨에서 검증한다.

m4t12

객체의 동등성

List.contains 메서드는 해당 리스트(o)가 Objects.equals(o, e)를 만족하는 원소 e를 한 개 이상 포함할 경우에 true를 반환한다. (역도 성립한다)

validate-duplicate

리스트의 원소는 ItemOrderInput 객체이므로 ItemOrderInput 클래스에 contains 메서드를 오버라이딩해서 두 인스턴스를 같다고 판단하는 기준을 정해주면 된다.

equality

equality vs hashCode

프로그래밍은 수학의 부분집합이다. 집합론에는 동치관계라는 개념이 있다.
어떤 두 대상이 같다라는 관계를 수학적으로 정의한 것이다.
예를 들어 법(modulus) 5에 대해서 1과 6은 같다(동치).

Java에는 두 대상(인스턴스)의 동치 관계를 equalityhashCode 두 가지 메서드로 판단한다.
모든 객체가 상속하는 Object 클래스에 정의된 두 메서드는 오버라이딩 하지 않으면 기본적으로 인스턴스의 메모리상의 주소에 의존한다.
직접 만든 클래스를 컬렉션의 원소로 사용할 때 두 메서드를 적절히 오버라이딩 하여 사용할 수 있다.

  • HashSet - 내부적으로 원소들의 동등성을 hashCode를 사용하여 비교한다.
  • List - 내부적으로 원소들의 동등성을 equality를 사용하여 비교한다.

동등성 학습테스트

Bar BarTest

Foo FooTest

order 도메인

주문에 대한 비즈니스 특화 클래스들을 모아둔 패키지

ItemOrder

“바비큐립-2” 와 같은 상품 한 개(item)에 대한 주문을 추상화한 클래스

ItemOrder

식당에서 판매하는 상품 한 개를 추상화 한 enum 클래스

MenuItem-1

MenuItem-2

Category

특정 상품의 분류를 표현한다. 상품의 분류에 따라 적용되는 서비스 정책이 있기 때문에 필요하다.

  • 음료만 주문 시, 주문할 수 없습니다.
  • 평일 할인(일요일~목요일): 평일에는 디저트 메뉴를 메뉴 1개당 2,023원 할인
  • 주말 할인(금요일, 토요일): 주말에는 메인 메뉴를 메뉴 1개당 2,023원 할인

OrderBasket

ItemOrder 컬렉션을 필드로 가지는 일급 컬렉션

OrderBasket-1

OrderBasket-2

m4t11을 통과하기 위해 추가한 메서드. 음료만 주문한 경우 DrinksOnlyOrderedException 예외를 던진다.

m4t11-impl

IO 패키지

입출력과 밀접한 관련이 있는 클래스들의 모음

ItemOrderInput

“티본스테이크-2” 와같은 상품 한 개의 주문에 대한 입력을 감싸는 Wrapper 클래스. 비즈니스 로직과 관계 없는 IO Level의 유효성 검사를 수행한다. DTO에 가깝다.

ItemOrderInput-1

ItemOrderInput-2

MultipleOrderInput

“티본스테이크-3,제로콜라-2,초코케이크-3,시저샐러드-2” 형태의 주문 전체를 표현하는 클래스. ItemOrderInput 에 대한 일급 컬렉션이다.

MultipleOrderInput

마무리

오늘 미션 진행하는데 걸린 시간

elapsed-time

reference

Comments