ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,76 @@
+package christmas.controller;
+
+import christmas.domain.Badge;
+import christmas.domain.Benefits;
+import christmas.domain.Convertor;
+import christmas.domain.Date;
+import christmas.domain.EventManager;
+import christmas.domain.Orders;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+
+public class EventController {
+    public void start() {
+        OutputView.printWelcome();
+        Date date = createDate();
+        Orders orders = createOrders();
+        int totalOrderAmount = createTotalOrderAmount(orders);
+        OutputView.printGift(orders.hasGift());
+        Benefits benefits = createBenefits(orders, date);
+        int totalBenefitAmount = createTotalBenefitAmount(benefits);
+        createPaymentAmount(orders, totalOrderAmount, totalBenefitAmount);
+        createBadge(benefits, totalBenefitAmount);
+    }
+
+    private Date createDate() {
+        while (true) {
+            try {
+                Date date = new Date(InputView.readDate());
+                OutputView.printPreview(date);
+                return date;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e);
+            }
+        }
+    }
+
+    private Orders createOrders() {
+        while (true) {
+            try {
+                Orders orders = Convertor.toOrders(InputView.readOrder());
+                OutputView.printOrders(orders);
+                return orders;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e);
+            }
+        }
+    }
+
+    private int createTotalOrderAmount(Orders orders) {
+        int totalOrderAmount = orders.calculateTotalAmount();
+        OutputView.printTotalOrderAmount(totalOrderAmount);
+        return totalOrderAmount;
+    }
+
+    private Benefits createBenefits(Orders orders, Date date) {
+        Benefits benefits = EventManager.toBenefits(orders, date);
+        OutputView.printBenefitDetail(benefits);
+        return benefits;
+    }
+
+    private int createTotalBenefitAmount(Benefits benefits) {
+        int totalBenefitAmount = benefits.calculateTotalBenefitAmount();
+        OutputView.printTotalBenefitAmount(totalBenefitAmount);
+        return totalBenefitAmount;
+    }
+
+    private void createPaymentAmount(Orders orders, int totalOrderAmount, int totalBenefitAmount) {
+        int paymentAmount = orders.calculatePaymentAmount(totalOrderAmount, totalBenefitAmount);
+        OutputView.printPaymentAmount(paymentAmount);
+    }
+
+    private void createBadge(Benefits benefits, int totalBenefitAmount) {
+        Badge badge = benefits.toEventBadge(totalBenefitAmount);
+        OutputView.printEventBadge(badge);
+    }
+}

리뷰: 다들 예외를 e 라고 표기하지만 그래도 error 라고 조금 더 상세하게 표현하는 것도 좋을 것 같습니다.
사실 저도 오라고 했었는데 어떤 분이 리뷰때 이러한 부분을 언급한 것을 본 적이 있어서요
@@ -0,0 +1,48 @@
+package christmas.domain;
+
+public enum Menu {
+    MUSHROOM_SOUP("양송이수프", 6_000, "애피타이저"),
+    TAPAS("타파스", 5_500, "애피타이저"),
+    CAESAR_SALAD("시저샐러드", 8_000, "애피타이저"),
+    T_BONE_STEAK("티본스테이크", 55_000, "메인"),
+    BBQ_RIBS("바비큐립", 54_000, "메인"),
+    SEAFOOD_PASTA("해산물파스타", 35_000, "메인"),
+    CHRISTMAS_PASTA("크리스마스파스타", 25_000, "메인"),
+    CHOCOLATE_CAKE("초코케이크", 15_000, "디저트"),
+    ICE_CREAM("아이스크림", 5_000, "디저트"),
+    ZERO_COKE("제로콜라", 3_000, "음료"),
+    RED_WINE("레드와인", 60_000, "음료"),
+    CHAMPAGNE("샴페인", 25_000, "음료"),
+    NONE("없음", 0, "없음");
+
+    private final String menuName;
+    private final int price;
+    private final String type;
+
+    Menu(String menuName, int price, String type) {
+        this.menuName = menuName;
+        this.price = price;
+        this.type = type;
+    }
+
+    public static Menu from(String menuName) {
+        for (Menu menu : values()) {
+            if (menu.getMenuName().equals(menuName)) {
+                return menu;
+            }
+        }
+        return NONE;
+    }
+
+    public String getMenuName() {
+        return menuName;
+    }
+
+    public int getPrice() {
+        return price;
+    }
+
+    public String getType() {
+        return type;
+    }
+}

리뷰: Stream을 이용해 메뉴가 포함된 리스트를 만들어 contains로 확인하는 게 조금 더 간결해 보일수도 있을 것 같은데 어떻게 생각하시나요??
@@ -0,0 +1,17 @@
+package christmas.domain;
+
+public enum Error {
+    INVALID_DATE("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요."),
+    INVALID_ORDER("[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요."),
+    INVALID_COUNT("[ERROR] 메뉴는 한 번에 최대 20개까지만 주문할 수 있습니다. 다시 입력해 주세요"),
+    INVALID_TYPE("[ERROR] 음료만 주문 시, 주문할 수 없습니다. 다시 입력해 주세요");
+    private final String message;
+
+    Error(String message) {
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

리뷰: [Error] 은 공통부분이다보니 따로 빼두어서 불러올때 this message = " [ error ]"+ message 로 해도 괜찮을 것 같은데 어떻게 생각하시나요?
@@ -0,0 +1,76 @@
+package christmas.controller;
+
+import christmas.domain.Badge;
+import christmas.domain.Benefits;
+import christmas.domain.Convertor;
+import christmas.domain.Date;
+import christmas.domain.EventManager;
+import christmas.domain.Orders;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+
+public class EventController {
+    public void start() {
+        OutputView.printWelcome();
+        Date date = createDate();
+        Orders orders = createOrders();
+        int totalOrderAmount = createTotalOrderAmount(orders);
+        OutputView.printGift(orders.hasGift());
+        Benefits benefits = createBenefits(orders, date);
+        int totalBenefitAmount = createTotalBenefitAmount(benefits);
+        createPaymentAmount(orders, totalOrderAmount, totalBenefitAmount);
+        createBadge(benefits, totalBenefitAmount);
+    }
+
+    private Date createDate() {
+        while (true) {
+            try {
+                Date date = new Date(InputView.readDate());
+                OutputView.printPreview(date);
+                return date;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e);
+            }
+        }
+    }
+
+    private Orders createOrders() {
+        while (true) {
+            try {
+                Orders orders = Convertor.toOrders(InputView.readOrder());
+                OutputView.printOrders(orders);
+                return orders;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e);
+            }
+        }
+    }
+
+    private int createTotalOrderAmount(Orders orders) {
+        int totalOrderAmount = orders.calculateTotalAmount();
+        OutputView.printTotalOrderAmount(totalOrderAmount);
+        return totalOrderAmount;
+    }
+
+    private Benefits createBenefits(Orders orders, Date date) {
+        Benefits benefits = EventManager.toBenefits(orders, date);
+        OutputView.printBenefitDetail(benefits);
+        return benefits;
+    }
+
+    private int createTotalBenefitAmount(Benefits benefits) {
+        int totalBenefitAmount = benefits.calculateTotalBenefitAmount();
+        OutputView.printTotalBenefitAmount(totalBenefitAmount);
+        return totalBenefitAmount;
+    }
+
+    private void createPaymentAmount(Orders orders, int totalOrderAmount, int totalBenefitAmount) {
+        int paymentAmount = orders.calculatePaymentAmount(totalOrderAmount, totalBenefitAmount);
+        OutputView.printPaymentAmount(paymentAmount);
+    }
+
+    private void createBadge(Benefits benefits, int totalBenefitAmount) {
+        Badge badge = benefits.toEventBadge(totalBenefitAmount);
+        OutputView.printEventBadge(badge);
+    }
+}

리뷰: 전체적으로 create라는 메서드명을 사용했는데 create가 객체 생성의 느낌을 주는거같아서 다른 이름으로 메서드명을 작성해보는건 어떨까요 ?
@@ -0,0 +1,43 @@
+package christmas.domain;
+
+import static christmas.domain.Error.INVALID_ORDER;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class Convertor {
+    private static final String ORDERS_DELIMITER = ",";
+    private static final String ORDER_DELIMITER = "-";
+    private static final int MENU_INDEX = 0;
+    private static final int COUNT_INDEX = 1;
+    private static final String REGEXP_PATTERN_ORDER = "([가-힣]+)(-)(\\d+)";
+
+    public static Orders toOrders(String input) {
+        List<Order> orders = Arrays.stream(input.split(ORDERS_DELIMITER))
+                .map(String::trim)
+                .map(Convertor::toOrder)
+                .collect(Collectors.toList());
+        return new Orders(orders);
+    }
+
+    private static Order toOrder(String input) {
+        validatePattern(input);
+        String[] menus = input.split(ORDER_DELIMITER);
+        String menuName = menus[MENU_INDEX];
+        int count = Integer.parseInt(menus[COUNT_INDEX]);
+        return new Order(menuName, count);
+    }
+
+    private static void validatePattern(String input) {
+        if (!isValidPattern(input)) {
+            throw new IllegalArgumentException(INVALID_ORDER.getMessage());
+        }
+    }
+
+    private static boolean isValidPattern(String input) {
+        return Pattern.matches(REGEXP_PATTERN_ORDER, input);
+    }
+
+}

리뷰: 정적 메소드로 사용하는 기준이 궁금합니다. 프리코스 기간동안 미션하면서 써보기는 했는데 어떨때 써야할지 잘 모르겠어서요
@@ -0,0 +1,24 @@
+package christmas.domain;
+
+public enum Badge {
+    STAR("별", 5_000),
+    TREE("트리", 10_000),
+    SANTA("산타", 20_000),
+    NONE("없음", 0);
+
+    private final String type;
+    private final int amount;
+
+    Badge(String type, int amount) {
+        this.type = type;
+        this.amount = amount;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public int getAmount() {
+        return amount;
+    }
+}

리뷰: private을 지정해 주지 않은 이유가 따로 있나요?
@@ -0,0 +1,56 @@
+package christmas.domain;
+
+
+import static christmas.domain.Badge.NONE;
+import static christmas.domain.Badge.SANTA;
+import static christmas.domain.Badge.STAR;
+import static christmas.domain.Badge.TREE;
+
+import java.util.Map;
+
+public class Benefits {
+    private final Map<Event, Integer> benefits;
+
+    public Benefits(Map<Event, Integer> benefits) {
+        this.benefits = benefits;
+    }
+
+    public int calculateTotalBenefitAmount() {
+        return benefits.values()
+                .stream()
+                .mapToInt(amount -> amount)
+                .sum();
+    }
+
+    public Badge toEventBadge(int totalBenefit) {
+        if (isStarBadge(totalBenefit)) {
+            return STAR;
+        }
+        if (isTreeBadge(totalBenefit)) {
+            return TREE;
+        }
+        if (isSantaBadge(totalBenefit)) {
+            return SANTA;
+        }
+        return NONE;
+    }
+
+    private boolean isStarBadge(int totalBenefit) {
+        return totalBenefit >= STAR.getAmount() && totalBenefit < TREE.getAmount();
+    }
+
+    private boolean isTreeBadge(int totalBenefit) {
+        return totalBenefit >= TREE.getAmount() && totalBenefit < SANTA.getAmount();
+    }
+
+    private boolean isSantaBadge(int totalBenefit) {
+        return totalBenefit >= SANTA.getAmount();
+    }
+
+    public Map<Event, Integer> getBenefits() {
+        return benefits;
+    }
+}
+
+
+

리뷰: 두줄 개행이 들어간거 같아요 !!
다음번엔 자잘한 컨벤션도 챙기면 좋을거같아요
@@ -0,0 +1,51 @@
+package christmas.domain;
+
+import static christmas.domain.Error.INVALID_DATE;
+import static java.time.DayOfWeek.FRIDAY;
+import static java.time.DayOfWeek.SATURDAY;
+import static java.time.DayOfWeek.SUNDAY;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+
+public class Date {
+    private static final int MIN_DATE = 1;
+    private static final int MAX_DATE = 31;
+    private static final int THIS_YEAR = 2023;
+    private static final int THIS_MONTH = 12;
+    private static final int CHRISTMAS_DATE = 25;
+    private final int value;
+
+    public Date(int value) {
+        validateRange(value);
+        this.value = value;
+    }
+
+    public boolean isDayBeforeChristmas() {
+        return value <= CHRISTMAS_DATE;
+    }
+
+    public boolean isWeekend() {
+        DayOfWeek dayOfWeek = createDayOfWeek();
+        return dayOfWeek == FRIDAY || dayOfWeek == SATURDAY;
+    }
+
+    public boolean isStarDay() {
+        return createDayOfWeek() == SUNDAY || value == CHRISTMAS_DATE;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    private DayOfWeek createDayOfWeek() {
+        LocalDate localDate = LocalDate.of(THIS_YEAR, THIS_MONTH, value);
+        return localDate.getDayOfWeek();
+    }
+
+    private void validateRange(int value) {
+        if (value > MAX_DATE || value < MIN_DATE) {
+            throw new IllegalArgumentException(INVALID_DATE.getMessage());
+        }
+    }
+}
\ No newline at end of file

리뷰: Date라는 클래스가 validateRange도 그렇고 12월에만 한정된거 같은데 Date라고 class명을 짓는건 너무 포괄적이게 느껴져서 조금 더 구체적인 다른이름을 사용했다면 어떨까 싶습니다
@@ -0,0 +1,48 @@
+package christmas.domain;
+
+public enum Menu {
+    MUSHROOM_SOUP("양송이수프", 6_000, "애피타이저"),
+    TAPAS("타파스", 5_500, "애피타이저"),
+    CAESAR_SALAD("시저샐러드", 8_000, "애피타이저"),
+    T_BONE_STEAK("티본스테이크", 55_000, "메인"),
+    BBQ_RIBS("바비큐립", 54_000, "메인"),
+    SEAFOOD_PASTA("해산물파스타", 35_000, "메인"),
+    CHRISTMAS_PASTA("크리스마스파스타", 25_000, "메인"),
+    CHOCOLATE_CAKE("초코케이크", 15_000, "디저트"),
+    ICE_CREAM("아이스크림", 5_000, "디저트"),
+    ZERO_COKE("제로콜라", 3_000, "음료"),
+    RED_WINE("레드와인", 60_000, "음료"),
+    CHAMPAGNE("샴페인", 25_000, "음료"),
+    NONE("없음", 0, "없음");
+
+    private final String menuName;
+    private final int price;
+    private final String type;
+
+    Menu(String menuName, int price, String type) {
+        this.menuName = menuName;
+        this.price = price;
+        this.type = type;
+    }
+
+    public static Menu from(String menuName) {
+        for (Menu menu : values()) {
+            if (menu.getMenuName().equals(menuName)) {
+                return menu;
+            }
+        }
+        return NONE;
+    }
+
+    public String getMenuName() {
+        return menuName;
+    }
+
+    public int getPrice() {
+        return price;
+    }
+
+    public String getType() {
+        return type;
+    }
+}

리뷰: 여기도 접근 지정자가 따로 설정되지 않은 이유가 있을까요 ?
@@ -0,0 +1,92 @@
+package christmas.domain;
+
+import static christmas.domain.Error.INVALID_ORDER;
+import static christmas.domain.Menu.NONE;
+
+import java.util.Objects;
+
+public class Order {
+    private static final int MIN_ORDER_COUNT = 1;
+    private final String menuName;
+    private final int count;
+
+    public Order(String menuName, int count) {
+        validateMenuName(menuName);
+        validateCount(count);
+        this.menuName = menuName;
+        this.count = count;
+    }
+
+    public int calculateByMenu() {
+        Menu menu = Menu.from(menuName);
+        return menu.getPrice() * count;
+    }
+
+
+    public boolean isBeverage() {
+        Menu menu = Menu.from(menuName);
+        return menu.getType().equals("음료");
+    }
+
+    public int countDessert() {
+        if (isDessert()) {
+            return count;
+        }
+        return 0;
+    }
+
+    private boolean isDessert() {
+        Menu menu = Menu.from(menuName);
+        return menu.getType().equals("디저트");
+    }
+
+    public int countMain() {
+        if (isMain()) {
+            return count;
+        }
+        return 0;
+    }
+
+
+    private boolean isMain() {
+        Menu menu = Menu.from(menuName);
+        return menu.getType().equals("메인");
+    }
+
+    public String getMenuName() {
+        return menuName;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Order order) {
+            return menuName.equals(order.menuName);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(menuName);
+    }
+
+    private void validateMenuName(String menu) {
+        if (isInvalidMenu(menu)) {
+            throw new IllegalArgumentException(INVALID_ORDER.getMessage());
+        }
+    }
+
+    private boolean isInvalidMenu(String menu) {
+        return Menu.from(menu) == NONE;
+    }
+
+    private void validateCount(int count) {
+        if (count < MIN_ORDER_COUNT) {
+            throw new IllegalArgumentException(INVALID_ORDER.getMessage());
+        }
+    }
+}

리뷰: 아까 Type을 별도로 Enum 같은 객체로 관리 했더라면 "음료"-> 와 같은 string형으로 비교하지 않아도 됐을 거 같아요 !! 만약 Type의 이름이 바뀌게 됐을때 하나하나 다시 코드를 바꾸는 수고를 덜 수 있었을거 같습니다:D
@@ -0,0 +1,92 @@
+package christmas.domain;
+
+import static christmas.domain.Error.INVALID_ORDER;
+import static christmas.domain.Menu.NONE;
+
+import java.util.Objects;
+
+public class Order {
+    private static final int MIN_ORDER_COUNT = 1;
+    private final String menuName;
+    private final int count;
+
+    public Order(String menuName, int count) {
+        validateMenuName(menuName);
+        validateCount(count);
+        this.menuName = menuName;
+        this.count = count;
+    }
+
+    public int calculateByMenu() {
+        Menu menu = Menu.from(menuName);
+        return menu.getPrice() * count;
+    }
+
+
+    public boolean isBeverage() {
+        Menu menu = Menu.from(menuName);
+        return menu.getType().equals("음료");
+    }
+
+    public int countDessert() {
+        if (isDessert()) {
+            return count;
+        }
+        return 0;
+    }
+
+    private boolean isDessert() {
+        Menu menu = Menu.from(menuName);
+        return menu.getType().equals("디저트");
+    }
+
+    public int countMain() {
+        if (isMain()) {
+            return count;
+        }
+        return 0;
+    }
+
+
+    private boolean isMain() {
+        Menu menu = Menu.from(menuName);
+        return menu.getType().equals("메인");
+    }
+
+    public String getMenuName() {
+        return menuName;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Order order) {
+            return menuName.equals(order.menuName);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(menuName);
+    }
+
+    private void validateMenuName(String menu) {
+        if (isInvalidMenu(menu)) {
+            throw new IllegalArgumentException(INVALID_ORDER.getMessage());
+        }
+    }
+
+    private boolean isInvalidMenu(String menu) {
+        return Menu.from(menu) == NONE;
+    }
+
+    private void validateCount(int count) {
+        if (count < MIN_ORDER_COUNT) {
+            throw new IllegalArgumentException(INVALID_ORDER.getMessage());
+        }
+    }
+}

리뷰: hashCode를 사용하셨네요 !!!! 
혹시 hashCode를 사용한 이유를 여쭤봐도 될까요?👀
@@ -0,0 +1,106 @@
+package christmas.domain;
+
+import static christmas.domain.Error.INVALID_COUNT;
+import static christmas.domain.Error.INVALID_ORDER;
+import static christmas.domain.Error.INVALID_TYPE;
+
+import java.util.List;
+
+public class Orders {
+    private static final int MAX_TOTAL_ORDER_COUNT = 20;
+    private static final int LOWER_LIMIT_AMOUNT_FOR_BENEFIT = 10_000;
+    private static final int LOWER_LIMIT_AMOUNT_FOR_GIFT = 120_000;
+
+    private final List<Order> orders;
+
+
+    public Orders(List<Order> orders) {
+        validateDuplicated(orders);
+        validateTotalCount(orders);
+        validateType(orders);
+        this.orders = orders;
+    }
+
+    public int calculatePaymentAmount(int totalAmount, int totalBenefit) {
+        int paymentAmount = totalAmount - totalBenefit;
+        if (hasGift()) {
+            paymentAmount += Event.GIFT.getInitPrice();
+            paymentAmount = minusValueToZero(paymentAmount);
+            return paymentAmount;
+        }
+        paymentAmount = minusValueToZero(paymentAmount);
+        return paymentAmount;
+    }
+
+    private int minusValueToZero(int paymentAmount) {
+        return Math.max(paymentAmount, 0);
+    }
+
+    public int calculateTotalAmount() {
+        return orders.stream()
+                .mapToInt(Order::calculateByMenu)
+                .sum();
+    }
+
+    public boolean isEligible() {
+        return calculateTotalAmount() > LOWER_LIMIT_AMOUNT_FOR_BENEFIT;
+    }
+
+    public boolean hasGift() {
+        return calculateTotalAmount() >= LOWER_LIMIT_AMOUNT_FOR_GIFT;
+    }
+
+
+    public int countDesserts() {
+        return orders.stream()
+                .mapToInt(Order::countDessert)
+                .sum();
+    }
+
+    public int countMains() {
+        return orders.stream()
+                .mapToInt(Order::countMain)
+                .sum();
+    }
+
+    public List<Order> getOrders() {
+        return orders;
+    }
+
+    private void validateDuplicated(List<Order> orders) {
+        if (isDuplicated(orders)) {
+            throw new IllegalArgumentException(INVALID_ORDER.getMessage());
+        }
+    }
+
+    private boolean isDuplicated(List<Order> orders) {
+        return orders.stream()
+                .distinct()
+                .count() != orders.size();
+    }
+
+    private void validateTotalCount(List<Order> orders) {
+        if (calculateTotalCount(orders) > MAX_TOTAL_ORDER_COUNT) {
+            throw new IllegalArgumentException(INVALID_COUNT.getMessage());
+        }
+    }
+
+    private int calculateTotalCount(List<Order> orders) {
+        return orders.stream()
+                .mapToInt(Order::getCount)
+                .sum();
+    }
+
+    private void validateType(List<Order> orders) {
+        if (isInvalidType(orders)) {
+            throw new IllegalArgumentException(INVALID_TYPE.getMessage());
+        }
+    }
+
+    private boolean isInvalidType(List<Order> orders) {
+        return orders.stream()
+                .allMatch(Order::isBeverage);
+    }
+
+
+}

리뷰: Benefit과 gif의 limit 금액를 Order에서 정해주는것보다 Benefit에 책임을 물려서 검증하는건 어땠을까요?
@@ -0,0 +1,25 @@
+package christmas.view;
+
+enum Notice {
+    WELCOME("안녕하세요! 우테코 식당 12월 이벤트 플래너입니다."),
+    ASK_DATE_OF_VISIT("12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)"),
+    ASK_MENU_AND_COUNT("주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)"),
+    PREVIEW("12월 %s일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!%n"),
+    ORDER_MENU("\n<주문 메뉴>"),
+    TOTAL_ORDER_AMOUNT("\n<할인 전 총주문 금액>"),
+    GIFT_MENU("\n<증정 메뉴>"),
+    BENEFIT_LIST("\n<혜택 내역>"),
+    TOTAL_BENEFIT_AMOUNT("\n<총혜택 금액>"),
+    TOTAL_PAYMENT_AMOUNT("\n<할인 후 예상 결제 금액>"),
+    EVENT_BADGE("\n<12월 이벤트 배지>");
+
+    private final String message;
+
+    Notice(String message) {
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

리뷰: %s일 사용하신 것처럼 12월도 동적으로 처리해볼 수 있을거 같아요 :) 👍
@@ -0,0 +1,38 @@
+package christmas.domain;
+
+import static christmas.domain.Badge.NONE;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+class BenefitsTest {
+    Benefits benefits;
+
+    @Test
+    @DisplayName("혜택의 총합 계산")
+    void calculateTotalBenefit() {
+        int totalBenefit = benefits.calculateTotalBenefitAmount();
+        assertThat(totalBenefit).isEqualTo(31246);
+    }
+
+    @ParameterizedTest
+    @DisplayName("총 혜택 금액에 따른 뱃지 지급")
+    @CsvSource(value = {"5500,별", "10500,트리", "21000,산타"})
+    void toEventBadge(int input, String expect) {
+        Badge badge = benefits.toEventBadge(input);
+        if (badge != NONE) {
+            assertThat(badge.getType()).isEqualTo(expect);
+        }
+    }
+
+    @BeforeEach
+    void setUp() {
+        Date date = new Date(3);
+        Orders orders = Convertor.toOrders("티본스테이크-1,바비큐립-1,초코케이크-2,제로콜라-1");
+        benefits = EventManager.toBenefits(orders, date);
+    }
+}
\ No newline at end of file

리뷰: CsvSouce가 있었군요 ?!!! 저는 이걸 몰라서 한가지 변수로만 테스트 코드를 작성하느라 애먹은 부분이 있었는데 ,, 배워갑니다 :O 유용하게 쓸 수 있을거같아요