From 082da76e383520fc80f5fe1f374b12c12fc693e9 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 9 Mar 2022 13:27:51 +0900 Subject: [PATCH 01/40] =?UTF-8?q?doc(feedback):=202=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=ED=94=BC=EB=93=9C=EB=B0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index eb45bbb33..5f1bc4152 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ - [ ] 포함된 상품에는 수량이 있다. - [ ] 등록된 메뉴들을 조회할 수 있다. - [ ] 진열 여부를 변경할 수 있다. + - [ ] 메뉴에 포함된 상품별 총 금액(상품 가격 * 상품 수량)의 합보다 작아야 진열할 수 있다. - [ ] 이름에 비속어를 사용할 수 없다. - [ ] 가격을 변경할 수 있다. - [ ] 가격은 0원 이상이어야 한다. @@ -110,6 +111,8 @@ - [x] `가격, 진열 여부를 변경할 수 있다.` - 여러 항목에 대한 공통 행위를 가지더라도 행위의 조건이 다르다면 분리하는 것이 요구사항을 명확하게 전달할 수 있다. +- [x] 진열여부를 변경할 수 있다. + - 진열시 예외 조건 누락됨. - [x] `식탁을 정리할 수 있다.` - 행위에 대한 조건이 누락됨. - [x] `식당 내 식사는 빈 식탁이 있어야 한다.` From 45dfbac53f2881daebc709ec724d7806f694cb5e Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 9 Mar 2022 17:30:46 +0900 Subject: [PATCH 02/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../application/MenuGroupFixture.java | 23 ++++++ .../application/MenuGroupServiceTest.java | 82 +++++++++++++++++++ .../ui/MenuGroupRestControllerTest.java | 69 ++++++++++++++++ src/test/resources/application.properties | 1 + 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/test/java/kitchenpos/application/MenuGroupFixture.java create mode 100644 src/test/java/kitchenpos/application/MenuGroupServiceTest.java create mode 100644 src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java create mode 100644 src/test/resources/application.properties diff --git a/README.md b/README.md index 5f1bc4152..370ad8ace 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ - [ ] 1개 이상의 상품을 포함한다. - [ ] 등록되지 않은 상품은 포함할 수 없다. - 메뉴 그룹 - - [ ] `이름`이 있다. - - [ ] 등록된 모든 메뉴 그룹을 조회할 수 있다. + - [x] `이름`이 있다. + - [x] 등록된 모든 메뉴 그룹을 조회할 수 있다. - 식탁 - [ ] `이름`, `손님 수`, `착석 여부`가 있다. - [ ] 식탁의 기본 상태는 0명의 손님이며 비어있다. diff --git a/src/test/java/kitchenpos/application/MenuGroupFixture.java b/src/test/java/kitchenpos/application/MenuGroupFixture.java new file mode 100644 index 000000000..b71fc5de1 --- /dev/null +++ b/src/test/java/kitchenpos/application/MenuGroupFixture.java @@ -0,0 +1,23 @@ +package kitchenpos.application; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import kitchenpos.domain.MenuGroup; + +public class MenuGroupFixture { + + public static final MenuGroup 세트메뉴 = new MenuGroup(); + public static final MenuGroup 추천메뉴 = new MenuGroup(); + public static final List 메뉴판 = Arrays.asList(세트메뉴, 추천메뉴); + + static { + initialize(세트메뉴, "세트메뉴"); + initialize(추천메뉴, "추천메뉴"); + } + + private static void initialize(MenuGroup menuGroup, String name) { + menuGroup.setId(UUID.randomUUID()); + menuGroup.setName(name); + } +} diff --git a/src/test/java/kitchenpos/application/MenuGroupServiceTest.java b/src/test/java/kitchenpos/application/MenuGroupServiceTest.java new file mode 100644 index 000000000..48d389c56 --- /dev/null +++ b/src/test/java/kitchenpos/application/MenuGroupServiceTest.java @@ -0,0 +1,82 @@ +package kitchenpos.application; + +import static kitchenpos.application.MenuGroupFixture.메뉴판; +import static kitchenpos.application.MenuGroupFixture.세트메뉴; +import static kitchenpos.application.MenuGroupFixture.추천메뉴; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +import java.util.List; +import kitchenpos.domain.MenuGroup; +import kitchenpos.domain.MenuGroupRepository; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayName("메뉴 그룹") +@ExtendWith(MockitoExtension.class) +class MenuGroupServiceTest { + + @Mock + private MenuGroupRepository menuGroupRepository; + + @InjectMocks + private MenuGroupService menuGroupService; + + @DisplayName("이름이 없으면 예외 발생") + @ParameterizedTest(name = "이름: [{arguments}]") + @NullAndEmptySource + void createNonameException(String name) { + //given + MenuGroup 이름_없는_메뉴_그룹 = new MenuGroup(); + 이름_없는_메뉴_그룹.setName(name); + + //when + ThrowingCallable actual = () -> menuGroupService.create(이름_없는_메뉴_그룹); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 그룹 생성") + @Test + void create() { + //given + given(menuGroupRepository.save(any(MenuGroup.class))).willReturn(세트메뉴); + + //when + MenuGroup menuGroup = menuGroupService.create(세트메뉴); + + //then + assertAll( + () -> assertThat(menuGroup.getId()).isNotNull(), + () -> assertThat(menuGroup.getName()).isEqualTo(세트메뉴.getName()) + ); + } + + @DisplayName("모든 메뉴 그룹 조회") + @Test + void findAll() { + //given + given(menuGroupRepository.findAll()).willReturn(메뉴판); + + //when + List menuGroups = menuGroupService.findAll(); + + //then + assertAll( + () -> assertThat(menuGroups).hasSize(2), + () -> assertThat(menuGroups).extracting("name") + .containsExactly(세트메뉴.getName(), 추천메뉴.getName()) + ); + } +} diff --git a/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java b/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java new file mode 100644 index 000000000..46dcb97dc --- /dev/null +++ b/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java @@ -0,0 +1,69 @@ +package kitchenpos.ui; + +import static kitchenpos.application.MenuGroupFixture.메뉴판; +import static kitchenpos.application.MenuGroupFixture.세트메뉴; +import static kitchenpos.application.MenuGroupFixture.추천메뉴; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import kitchenpos.application.MenuGroupService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(MenuGroupRestController.class) +class MenuGroupRestControllerTest { + + @Autowired + private MockMvc webMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private MenuGroupService menuGroupService; + + @DisplayName("메뉴그룹 생성") + @Test + void create() throws Exception { + //when + String body = objectMapper.writeValueAsString(세트메뉴); + + //when + given(menuGroupService.create(any())).willReturn(세트메뉴); + + //then + webMvc.perform(post("/api/menu-groups") + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andDo(print()) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").isNotEmpty()) + .andExpect(jsonPath("$.name").value(세트메뉴.getName())); + } + + @DisplayName("메뉴그룹 조회") + @Test + void findAll() throws Exception { + //when + given(menuGroupService.findAll()).willReturn(메뉴판); + + //then + webMvc.perform(get("/api/menu-groups") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].name").value(세트메뉴.getName())) + .andExpect(jsonPath("$[1].name").value(추천메뉴.getName())); + } +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 000000000..e2cb31553 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1 @@ +server.servlet.encoding.force-response=true From dea2082072b57735c3f32c33a7ccb639a3fa3604 Mon Sep 17 00:00:00 2001 From: yongju Date: Fri, 11 Mar 2022 08:33:23 +0900 Subject: [PATCH 03/40] =?UTF-8?q?test:=20=EC=83=81=ED=92=88=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +- .../application/FakePurgomalumClient.java | 16 ++ .../kitchenpos/application/MenuFixture.java | 20 ++ .../application/MenuProductFixture.java | 20 ++ .../application/ProductFixture.java | 23 +++ .../application/ProductServiceTest.java | 176 ++++++++++++++++++ src/test/resources/application.properties | 3 + 7 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 src/test/java/kitchenpos/application/FakePurgomalumClient.java create mode 100644 src/test/java/kitchenpos/application/MenuFixture.java create mode 100644 src/test/java/kitchenpos/application/MenuProductFixture.java create mode 100644 src/test/java/kitchenpos/application/ProductFixture.java create mode 100644 src/test/java/kitchenpos/application/ProductServiceTest.java diff --git a/README.md b/README.md index 370ad8ace..c9a2db1e1 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,14 @@ 식당에서 사용하는 주문관리 시스템을 구축한다. - 상품 - - [ ] `이름`과 `가격`이 있다. - - [ ] 등록된 상품들을 조회할 수 있다. - - [ ] 이름에 비속어를 사용할 수 없다. - - [ ] 가격을 변경할 수 있다. - - [ ] 가격은 0원 이상이어야 한다. - - [ ] 가격이 해당 상품을 포함하는 메뉴의 가격보다 크면 메뉴를 진열하지 않는다. + - [x] `이름`과 `가격`이 있다. + - [x] 등록된 상품들을 조회할 수 있다. + - [x] 이름에 비속어를 사용할 수 없다. + - [x] 가격은 0원 이상이어야 한다. + - [x] 가격을 변경할 수 있다. + - [x] 0원 이하의 가격으로 변경할 수 없다. + - [x] 등록되지 않은 상품은 가격을 변경할 수 없다. + - [x] 가격이 해당 상품을 포함하는 메뉴의 가격보다 크면 메뉴를 진열하지 않는다. - 메뉴 - [ ] `이름`, `가격`, `메뉴 그룹`, `진열 여부`, `1개 이상의 상품`이 있다. - [ ] 포함된 상품에는 수량이 있다. diff --git a/src/test/java/kitchenpos/application/FakePurgomalumClient.java b/src/test/java/kitchenpos/application/FakePurgomalumClient.java new file mode 100644 index 000000000..d7b16db24 --- /dev/null +++ b/src/test/java/kitchenpos/application/FakePurgomalumClient.java @@ -0,0 +1,16 @@ +package kitchenpos.application; + +import kitchenpos.infra.PurgomalumClient; +import org.springframework.boot.web.client.RestTemplateBuilder; + +public class FakePurgomalumClient extends PurgomalumClient { + + public FakePurgomalumClient(RestTemplateBuilder restTemplateBuilder) { + super(new RestTemplateBuilder()); + } + + @Override + public boolean containsProfanity(String text) { + return "비속어".equals(text); + } +} diff --git a/src/test/java/kitchenpos/application/MenuFixture.java b/src/test/java/kitchenpos/application/MenuFixture.java new file mode 100644 index 000000000..0ad34e60c --- /dev/null +++ b/src/test/java/kitchenpos/application/MenuFixture.java @@ -0,0 +1,20 @@ +package kitchenpos.application; + +import static kitchenpos.application.MenuProductFixture.메뉴_뿌링클; +import static kitchenpos.application.MenuProductFixture.메뉴_콜라; + +import java.math.BigDecimal; +import java.util.Arrays; +import kitchenpos.domain.Menu; + +public class MenuFixture { + + public static final Menu 뿌링클_세트 = new Menu(); + + static { + 뿌링클_세트.setMenuProducts(Arrays.asList(메뉴_뿌링클, 메뉴_콜라)); + 뿌링클_세트.setPrice(BigDecimal.valueOf(11_000L)); + 뿌링클_세트.setDisplayed(true); + } + +} diff --git a/src/test/java/kitchenpos/application/MenuProductFixture.java b/src/test/java/kitchenpos/application/MenuProductFixture.java new file mode 100644 index 000000000..56333c8ea --- /dev/null +++ b/src/test/java/kitchenpos/application/MenuProductFixture.java @@ -0,0 +1,20 @@ +package kitchenpos.application; + +import static kitchenpos.application.ProductFixture.뿌링클; +import static kitchenpos.application.ProductFixture.콜라; + +import kitchenpos.domain.MenuProduct; + +public class MenuProductFixture { + + public static final MenuProduct 메뉴_뿌링클 = new MenuProduct(); + public static final MenuProduct 메뉴_콜라 = new MenuProduct(); + + static { + 메뉴_뿌링클.setProduct(뿌링클); + 메뉴_뿌링클.setQuantity(1L); + 메뉴_콜라.setProduct(콜라); + 메뉴_콜라.setQuantity(1L); + } + +} diff --git a/src/test/java/kitchenpos/application/ProductFixture.java b/src/test/java/kitchenpos/application/ProductFixture.java new file mode 100644 index 000000000..147d57665 --- /dev/null +++ b/src/test/java/kitchenpos/application/ProductFixture.java @@ -0,0 +1,23 @@ +package kitchenpos.application; + +import java.math.BigDecimal; +import java.util.UUID; +import kitchenpos.domain.Product; + +public class ProductFixture { + + public static final Product 뿌링클 = new Product(); + public static final Product 콜라 = new Product(); + + static { + initialize(뿌링클, "뿌링클", 10_000L); + initialize(콜라, "콜라", 2_000L); + } + + private static void initialize(Product product, String name, long price) { + product.setName(name); + product.setId(UUID.randomUUID()); + product.setPrice(BigDecimal.valueOf(price)); + } + +} diff --git a/src/test/java/kitchenpos/application/ProductServiceTest.java b/src/test/java/kitchenpos/application/ProductServiceTest.java new file mode 100644 index 000000000..a4f917809 --- /dev/null +++ b/src/test/java/kitchenpos/application/ProductServiceTest.java @@ -0,0 +1,176 @@ +package kitchenpos.application; + +import static kitchenpos.application.MenuFixture.뿌링클_세트; +import static kitchenpos.application.ProductFixture.뿌링클; +import static kitchenpos.application.ProductFixture.콜라; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; +import kitchenpos.domain.MenuRepository; +import kitchenpos.domain.Product; +import kitchenpos.domain.ProductRepository; +import kitchenpos.infra.PurgomalumClient; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayName("상품") +@ExtendWith(MockitoExtension.class) +class ProductServiceTest { + + @Mock + private ProductRepository productRepository; + @Mock + private MenuRepository menuRepository; + @Mock(lenient = true) + private PurgomalumClient purgomalumClient; + + @InjectMocks + private ProductService productService; + + @DisplayName("상품 가격 0원 이하 불가") + @ParameterizedTest(name = "상품금액: [{arguments}]") + @MethodSource("priceException") + void createPriceException(BigDecimal price) { + //given + Product product = 상품_금액(price); + + //when + ThrowingCallable actual = () -> productService.create(product); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + private static Stream priceException() { + return Stream.of( + Arguments.of((BigDecimal) null), + Arguments.of(BigDecimal.valueOf(-1)) + ); + } + + @DisplayName("상품의 이름에 비속어 사용 불가") + @ParameterizedTest(name = "상품 이름: [{arguments}]") + @MethodSource("constructorNameException") + void createNameException(String name) { + //given + Product product = new Product(); + product.setPrice(BigDecimal.valueOf(10_000L)); + product.setName(name); + + given(purgomalumClient.containsProfanity("비속어")).willReturn(true); + + //when + ThrowingCallable actual = () -> productService.create(product); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + private static Stream constructorNameException() { + return Stream.of( + Arguments.of((String) null), + Arguments.of("비속어") + ); + } + + @DisplayName("가격 변경") + @ParameterizedTest(name = "변경할 가격: [{0}], 진열 여부: [{1}]") + @MethodSource("changePrice") + void changePrice(long price, boolean expectedDisplayed) { + //given + 뿌링클_세트.setDisplayed(true); + Product 변경할_금액 = 상품_금액(price); + + given(productRepository.findById(any(UUID.class))).willReturn(Optional.of(뿌링클)); + given(menuRepository.findAllByProductId(any(UUID.class))).willReturn(Collections.singletonList(뿌링클_세트)); + + //when + Product product = productService.changePrice(뿌링클.getId(), 변경할_금액); + + //then + assertAll( + () -> assertThat(product.getPrice()).isEqualTo(BigDecimal.valueOf(price)), + () -> assertThat(뿌링클_세트.isDisplayed()).isEqualTo(expectedDisplayed) + ); + } + + private static Stream changePrice() { + return Stream.of( + Arguments.of(8_000L, false), + Arguments.of(15_000L, true) + ); + } + + @DisplayName("가격 변경 예외") + @ParameterizedTest(name = "변경할 가격: [{arguments}]") + @MethodSource("priceException") + void changePriceException(BigDecimal price) { + //given + Product 뿌링클_가격_변경 = 상품_금액(price); + + //when + ThrowingCallable actual = () -> productService.changePrice(뿌링클.getId(), 뿌링클_가격_변경); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + + } + + @DisplayName("등록되지 않은 상품의 가격 변경 예외") + @Test + void changePriceNotExistProductException() { + //given + Product 뿌링클_가격_변경 = 상품_금액(10_000L); + + given(productRepository.findById(any(UUID.class))).willThrow(IllegalArgumentException.class); + + //when + ThrowingCallable actual = () -> productService.changePrice(뿌링클.getId(), 뿌링클_가격_변경); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + + } + + @DisplayName("모든 상품 조회") + @Test + void findAll() { + //given + given(productRepository.findAll()).willReturn(Arrays.asList(뿌링클, 콜라)); + + //when + List products = productService.findAll(); + + //then + assertThat(products).containsExactly(뿌링클, 콜라); + + } + + private Product 상품_금액(long price) { + return 상품_금액(BigDecimal.valueOf(price)); + } + + private Product 상품_금액(BigDecimal price) { + Product product = new Product(); + product.setPrice(price); + return product; + } +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index e2cb31553..259681215 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1 +1,4 @@ server.servlet.encoding.force-response=true +spring.datasource.url=jdbc:h2:~/test;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.username=sa +spring.flyway.enabled=true From 0cf35a9c56bd958417885e9edc950800eed76873 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 12 Mar 2022 10:49:58 +0900 Subject: [PATCH 04/40] =?UTF-8?q?fix:=20=EC=83=81=ED=92=88=20=EA=B0=80?= =?UTF-8?q?=EA=B2=A9=20=EB=B3=80=EA=B2=BD=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상품을 포함하는 메뉴의 진열여부 변경 기준이 상품들의 가격을 합산 하지 않고 있었음 --- src/main/java/kitchenpos/application/ProductService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/kitchenpos/application/ProductService.java b/src/main/java/kitchenpos/application/ProductService.java index 88cac9dad..3d86f06d5 100644 --- a/src/main/java/kitchenpos/application/ProductService.java +++ b/src/main/java/kitchenpos/application/ProductService.java @@ -57,9 +57,9 @@ public Product changePrice(final UUID productId, final Product request) { for (final Menu menu : menus) { BigDecimal sum = BigDecimal.ZERO; for (final MenuProduct menuProduct : menu.getMenuProducts()) { - sum = menuProduct.getProduct() + sum = sum.add(menuProduct.getProduct() .getPrice() - .multiply(BigDecimal.valueOf(menuProduct.getQuantity())); + .multiply(BigDecimal.valueOf(menuProduct.getQuantity()))); } if (menu.getPrice().compareTo(sum) > 0) { menu.setDisplayed(false); From ae6309bacf9ace3c3654d2c02777906eb00021d4 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 12 Mar 2022 15:36:48 +0900 Subject: [PATCH 05/40] =?UTF-8?q?test:=20=EC=8B=9D=ED=83=81=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +- .../application/OrderTableFixture.java | 22 ++ .../application/OrderTableServiceTest.java | 199 ++++++++++++++++++ 3 files changed, 229 insertions(+), 8 deletions(-) create mode 100644 src/test/java/kitchenpos/application/OrderTableFixture.java create mode 100644 src/test/java/kitchenpos/application/OrderTableServiceTest.java diff --git a/README.md b/README.md index c9a2db1e1..43c7167de 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,14 @@ - [x] `이름`이 있다. - [x] 등록된 모든 메뉴 그룹을 조회할 수 있다. - 식탁 - - [ ] `이름`, `손님 수`, `착석 여부`가 있다. - - [ ] 식탁의 기본 상태는 0명의 손님이며 비어있다. - - [ ] 모든 식탁을 조회할 수 있다. - - [ ] 손님이 앉을 수 있다. - - [ ] 손님이 앉으면 찬 상태다 - - [ ] 앉은 손님의 수를 변경할 수 있다. - - [ ] 주문 완료된 식탁만 정리할 수 있다. - - [ ] 정리된 식탁은 기본 상태가 된다. + - [x] `이름`, `손님 수`, `착석 여부`가 있다. + - [x] 식탁의 기본 상태는 0명의 손님이며 비어있다. + - [x] 모든 식탁을 조회할 수 있다. + - [x] 손님이 앉을 수 있다. + - [x] 손님이 앉으면 착석 상태다 + - [x] 앉은 손님의 수를 변경할 수 있다. + - [x] 주문 완료된 식탁만 정리할 수 있다. + - [x] 정리된 식탁은 기본 상태가 된다. - 주문 - [ ] `주문 유형`, `주문 메뉴의 수량 및 가격`이 있다. - [ ] 주문 유형은 `배달`, `포장`, `식당 내 식사`다. diff --git a/src/test/java/kitchenpos/application/OrderTableFixture.java b/src/test/java/kitchenpos/application/OrderTableFixture.java new file mode 100644 index 000000000..e8660f5cf --- /dev/null +++ b/src/test/java/kitchenpos/application/OrderTableFixture.java @@ -0,0 +1,22 @@ +package kitchenpos.application; + +import java.util.UUID; +import kitchenpos.domain.OrderTable; + +public class OrderTableFixture { + + public static final OrderTable 일번_테이블 = new OrderTable(); + public static final OrderTable 삼번_테이블 = new OrderTable(); + + static { + initialize(일번_테이블, "1번"); + initialize(삼번_테이블, "3번"); + } + + private static void initialize(OrderTable orderTable, String name) { + orderTable.setId(UUID.randomUUID()); + orderTable.setName(name); + orderTable.setNumberOfGuests(0); + orderTable.setEmpty(true); + } +} diff --git a/src/test/java/kitchenpos/application/OrderTableServiceTest.java b/src/test/java/kitchenpos/application/OrderTableServiceTest.java new file mode 100644 index 000000000..8600880a1 --- /dev/null +++ b/src/test/java/kitchenpos/application/OrderTableServiceTest.java @@ -0,0 +1,199 @@ +package kitchenpos.application; + + +import static kitchenpos.application.OrderTableFixture.삼번_테이블; +import static kitchenpos.application.OrderTableFixture.일번_테이블; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import kitchenpos.domain.OrderRepository; +import kitchenpos.domain.OrderStatus; +import kitchenpos.domain.OrderTable; +import kitchenpos.domain.OrderTableRepository; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayName("상품") +@ExtendWith(MockitoExtension.class) +class OrderTableServiceTest { + + @Mock + private OrderTableRepository orderTableRepository; + @Mock + private OrderRepository orderRepository; + + @InjectMocks + private OrderTableService orderTableService; + + @DisplayName("식탁 생성 예외 - 식탁 이름 없음") + @ParameterizedTest(name = "식탁 이름: [{arguments}]") + @NullAndEmptySource + void createException(String orderTableName) { + //given + OrderTable orderTable = 식탁_생성(orderTableName); + + //when + ThrowingCallable actual = () -> orderTableService.create(orderTable); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("식탁 생성") + @Test + void create() { + //given + OrderTable 신규_테이블 = 식탁_생성("3번"); + + given(orderTableRepository.save(any(OrderTable.class))).willReturn(삼번_테이블); + //when + OrderTable orderTable = orderTableService.create(신규_테이블); + + //then + assertAll( + () -> assertThat(orderTable.getName()).isEqualTo("3번"), + () -> assertThat(orderTable.getNumberOfGuests()).isZero(), + () -> assertThat(orderTable.isEmpty()).isTrue() + ); + } + + @DisplayName("손님 착석") + @Test + void sit() { + //given + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + + //when + OrderTable orderTable = orderTableService.sit(일번_테이블.getId()); + + boolean actual = orderTable.isEmpty(); + + //then + assertThat(actual).isFalse(); + } + + @DisplayName("식탁 정리 예외 - 주문완료되지 않은 식탁") + @Test + void clearException() { + //given + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + given(orderRepository.existsByOrderTableAndStatusNot(any(OrderTable.class), any(OrderStatus.class))) + .willReturn(true); + + //when + ThrowingCallable actual = () -> orderTableService.clear(일번_테이블.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("식탁 정리") + @Test + void clear() { + //given + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + given(orderRepository.existsByOrderTableAndStatusNot(any(OrderTable.class), any(OrderStatus.class))) + .willReturn(false); + + //when + OrderTable cleanTable = orderTableService.clear(일번_테이블.getId()); + + //then + assertAll( + () -> Assertions.assertThat(cleanTable.getNumberOfGuests()).isZero(), + () -> Assertions.assertThat(cleanTable.isEmpty()).isTrue() + ); + + } + + @DisplayName("손님 수 변경 예외 - 0명 미만으로 변경 불가") + @Test + void changeNumberOfGuestsException() { + //given + OrderTable 손님_수_변경 = 식탁_생성("1번 테이블 손님", -1); + + //when + ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("손님 수 변경 예외 - 착석하지 않은 식탁") + @Test + void tableIsEmptyThenChangeNumberOfGuestsException() { + //given + OrderTable 손님_수_변경 = 식탁_생성("1번 테이블 손님", 3); + + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + + //when + ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("손님 수 변경") + @Test + void changeNumberOfGuests() { + //given + OrderTable 손님_수_변경 = 식탁_생성("3번 테이블 손님", 3); + + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + orderTableService.sit(일번_테이블.getId()); + + //when + OrderTable orderTable = orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + + //then + assertAll( + () -> assertThat(orderTable.getNumberOfGuests()).isEqualTo(3), + () -> assertThat(orderTable.isEmpty()).isFalse() + ); + } + + @DisplayName("모든 식탁 조회") + @Test + void findAll() { + //given + given(orderTableRepository.findAll()).willReturn(Arrays.asList(일번_테이블, 삼번_테이블)); + + //when + List orderTables = orderTableService.findAll(); + + //then + assertAll( + () -> assertThat(orderTables).hasSize(2), + () -> assertThat(orderTables).containsExactly(일번_테이블, 삼번_테이블) + ); + } + + private OrderTable 식탁_생성(String orderTableName) { + OrderTable orderTable = new OrderTable(); + orderTable.setName(orderTableName); + return orderTable; + } + + private OrderTable 식탁_생성(String orderTableName, int numberOfGuests) { + OrderTable orderTable = 식탁_생성(orderTableName); + orderTable.setNumberOfGuests(numberOfGuests); + orderTable.setEmpty(false); + return orderTable; + } +} From 1d569db6dfbe460a19341f2c574f0a9c3ac2b4d8 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 12 Mar 2022 15:37:52 +0900 Subject: [PATCH 06/40] =?UTF-8?q?chore:=20=EC=8B=9D=ED=83=81=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=98=A4=ED=83=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/kitchenpos/application/OrderTableServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/kitchenpos/application/OrderTableServiceTest.java b/src/test/java/kitchenpos/application/OrderTableServiceTest.java index 8600880a1..d3dc609f4 100644 --- a/src/test/java/kitchenpos/application/OrderTableServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderTableServiceTest.java @@ -28,7 +28,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -@DisplayName("상품") +@DisplayName("식탁") @ExtendWith(MockitoExtension.class) class OrderTableServiceTest { From c35ac5c3124fc5b8c8a8f1eee45e4ade58e2cf5b Mon Sep 17 00:00:00 2001 From: yongju Date: Sun, 13 Mar 2022 10:30:52 +0900 Subject: [PATCH 07/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 +- .../kitchenpos/application/MenuService.java | 22 +- .../kitchenpos/application/MenuFixture.java | 10 +- .../application/MenuProductFixture.java | 26 +- .../application/MenuServiceTest.java | 330 ++++++++++++++++++ .../application/ProductFixture.java | 2 + 6 files changed, 383 insertions(+), 31 deletions(-) create mode 100644 src/test/java/kitchenpos/application/MenuServiceTest.java diff --git a/README.md b/README.md index 43c7167de..0ff7bcd71 100644 --- a/README.md +++ b/README.md @@ -13,18 +13,18 @@ - [x] 등록되지 않은 상품은 가격을 변경할 수 없다. - [x] 가격이 해당 상품을 포함하는 메뉴의 가격보다 크면 메뉴를 진열하지 않는다. - 메뉴 - - [ ] `이름`, `가격`, `메뉴 그룹`, `진열 여부`, `1개 이상의 상품`이 있다. - - [ ] 포함된 상품에는 수량이 있다. - - [ ] 등록된 메뉴들을 조회할 수 있다. - - [ ] 진열 여부를 변경할 수 있다. - - [ ] 메뉴에 포함된 상품별 총 금액(상품 가격 * 상품 수량)의 합보다 작아야 진열할 수 있다. - - [ ] 이름에 비속어를 사용할 수 없다. - - [ ] 가격을 변경할 수 있다. - - [ ] 가격은 0원 이상이어야 한다. - - [ ] 가격은 메뉴에 포함된 상품별 총 금액(상품 가격 * 상품 수량)의 합보다 작아야 한다. - - [ ] 하나의 메뉴 그룹에만 속한다. - - [ ] 1개 이상의 상품을 포함한다. - - [ ] 등록되지 않은 상품은 포함할 수 없다. + - [x] `이름`, `가격`, `메뉴 그룹`, `진열 여부`, `1개 이상의 상품`이 있다. + - [x] 포함된 상품에는 수량이 있다. + - [x] 등록된 메뉴들을 조회할 수 있다. + - [x] 진열 여부를 변경할 수 있다. + - [x] 메뉴에 포함된 상품별 총 금액(상품 가격 * 상품 수량)의 합보다 작아야 진열할 수 있다. + - [x] 이름에 비속어를 사용할 수 없다. + - [x] 가격을 변경할 수 있다. + - [x] 가격은 0원 이상이어야 한다. + - [x] 가격은 메뉴에 포함된 상품별 총 금액(상품 가격 * 상품 수량)의 합보다 작아야 한다. + - [x] 하나의 메뉴 그룹에만 속한다. + - [x] 1개 이상의 상품을 포함한다. + - [x] 등록되지 않은 상품은 포함할 수 없다. - 메뉴 그룹 - [x] `이름`이 있다. - [x] 등록된 모든 메뉴 그룹을 조회할 수 있다. diff --git a/src/main/java/kitchenpos/application/MenuService.java b/src/main/java/kitchenpos/application/MenuService.java index 0f3e4b7bc..b68950be5 100644 --- a/src/main/java/kitchenpos/application/MenuService.java +++ b/src/main/java/kitchenpos/application/MenuService.java @@ -91,13 +91,14 @@ public Menu changePrice(final UUID menuId, final Menu request) { } final Menu menu = menuRepository.findById(menuId) .orElseThrow(NoSuchElementException::new); + BigDecimal sum = BigDecimal.ZERO; for (final MenuProduct menuProduct : menu.getMenuProducts()) { - final BigDecimal sum = menuProduct.getProduct() + sum = sum.add(menuProduct.getProduct() .getPrice() - .multiply(BigDecimal.valueOf(menuProduct.getQuantity())); - if (price.compareTo(sum) > 0) { - throw new IllegalArgumentException(); - } + .multiply(BigDecimal.valueOf(menuProduct.getQuantity()))); + } + if (price.compareTo(sum) > 0) { + throw new IllegalArgumentException(); } menu.setPrice(price); return menu; @@ -107,13 +108,14 @@ public Menu changePrice(final UUID menuId, final Menu request) { public Menu display(final UUID menuId) { final Menu menu = menuRepository.findById(menuId) .orElseThrow(NoSuchElementException::new); + BigDecimal sum = BigDecimal.ZERO; for (final MenuProduct menuProduct : menu.getMenuProducts()) { - final BigDecimal sum = menuProduct.getProduct() + sum = sum.add(menuProduct.getProduct() .getPrice() - .multiply(BigDecimal.valueOf(menuProduct.getQuantity())); - if (menu.getPrice().compareTo(sum) > 0) { - throw new IllegalStateException(); - } + .multiply(BigDecimal.valueOf(menuProduct.getQuantity()))); + } + if (menu.getPrice().compareTo(sum) > 0) { + throw new IllegalStateException(); } menu.setDisplayed(true); return menu; diff --git a/src/test/java/kitchenpos/application/MenuFixture.java b/src/test/java/kitchenpos/application/MenuFixture.java index 0ad34e60c..7f92b8482 100644 --- a/src/test/java/kitchenpos/application/MenuFixture.java +++ b/src/test/java/kitchenpos/application/MenuFixture.java @@ -1,7 +1,8 @@ package kitchenpos.application; -import static kitchenpos.application.MenuProductFixture.메뉴_뿌링클; -import static kitchenpos.application.MenuProductFixture.메뉴_콜라; +import static kitchenpos.application.MenuGroupFixture.세트메뉴; +import static kitchenpos.application.MenuProductFixture.뿌링클_1개; +import static kitchenpos.application.MenuProductFixture.콜라_1개; import java.math.BigDecimal; import java.util.Arrays; @@ -12,7 +13,10 @@ public class MenuFixture { public static final Menu 뿌링클_세트 = new Menu(); static { - 뿌링클_세트.setMenuProducts(Arrays.asList(메뉴_뿌링클, 메뉴_콜라)); + 뿌링클_세트.setName("뿌링클 세트"); + 뿌링클_세트.setMenuGroup(세트메뉴); + 뿌링클_세트.setMenuGroupId(세트메뉴.getId()); + 뿌링클_세트.setMenuProducts(Arrays.asList(뿌링클_1개, 콜라_1개)); 뿌링클_세트.setPrice(BigDecimal.valueOf(11_000L)); 뿌링클_세트.setDisplayed(true); } diff --git a/src/test/java/kitchenpos/application/MenuProductFixture.java b/src/test/java/kitchenpos/application/MenuProductFixture.java index 56333c8ea..19fef9d2e 100644 --- a/src/test/java/kitchenpos/application/MenuProductFixture.java +++ b/src/test/java/kitchenpos/application/MenuProductFixture.java @@ -1,20 +1,34 @@ package kitchenpos.application; +import static kitchenpos.application.ProductFixture.맛초킹; import static kitchenpos.application.ProductFixture.뿌링클; import static kitchenpos.application.ProductFixture.콜라; import kitchenpos.domain.MenuProduct; +import kitchenpos.domain.Product; public class MenuProductFixture { - public static final MenuProduct 메뉴_뿌링클 = new MenuProduct(); - public static final MenuProduct 메뉴_콜라 = new MenuProduct(); + public static final MenuProduct 뿌링클_1개 = new MenuProduct(); + public static final MenuProduct 맛초킹_1개 = new MenuProduct(); + public static final MenuProduct 콜라_1개 = new MenuProduct(); + public static final MenuProduct 콜라_수량_오류 = new MenuProduct(); static { - 메뉴_뿌링클.setProduct(뿌링클); - 메뉴_뿌링클.setQuantity(1L); - 메뉴_콜라.setProduct(콜라); - 메뉴_콜라.setQuantity(1L); + initialize(뿌링클_1개, 뿌링클); + initialize(맛초킹_1개, 맛초킹); + initialize(콜라_1개, 콜라); + initialize(콜라_수량_오류, 콜라, -1L); + } + + private static void initialize(MenuProduct menuProduct, Product product) { + initialize(menuProduct, product, 1L); + } + + private static void initialize(MenuProduct menuProduct, Product product, long quantity) { + menuProduct.setProduct(product); + menuProduct.setProductId(product.getId()); + menuProduct.setQuantity(quantity); } } diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java new file mode 100644 index 000000000..3429619f6 --- /dev/null +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -0,0 +1,330 @@ +package kitchenpos.application; + +import static kitchenpos.application.MenuFixture.뿌링클_세트; +import static kitchenpos.application.MenuGroupFixture.세트메뉴; +import static kitchenpos.application.MenuProductFixture.맛초킹_1개; +import static kitchenpos.application.MenuProductFixture.콜라_1개; +import static kitchenpos.application.MenuProductFixture.콜라_수량_오류; +import static kitchenpos.application.ProductFixture.맛초킹; +import static kitchenpos.application.ProductFixture.뿌링클; +import static kitchenpos.application.ProductFixture.콜라; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; +import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuGroupRepository; +import kitchenpos.domain.MenuRepository; +import kitchenpos.domain.ProductRepository; +import kitchenpos.infra.PurgomalumClient; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayName("메뉴") +@ExtendWith(MockitoExtension.class) +class MenuServiceTest { + + @Mock + private MenuRepository menuRepository; + @Mock + private MenuGroupRepository menuGroupRepository; + @Mock + private ProductRepository productRepository; + @Mock(lenient = true) + private PurgomalumClient purgomalumClient; + + @InjectMocks + private MenuService menuService; + + private Menu 맛초킹_세트; + + @BeforeEach + void setUp() { + 맛초킹_세트 = new Menu(); + 맛초킹_세트.setName("맛초킹 세트"); + 맛초킹_세트.setMenuGroup(세트메뉴); + 맛초킹_세트.setMenuGroupId(세트메뉴.getId()); + 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)); + 맛초킹_세트.setPrice(BigDecimal.valueOf(11_000L)); + 맛초킹_세트.setDisplayed(true); + } + + @DisplayName("메뉴 생성 예외 - 메뉴 가격 0원 미만") + @Test + void createPriceUnderZeroException() { + //given + 맛초킹_세트.setPrice(BigDecimal.valueOf(-1L)); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 생성 예외 - 메뉴 그룹 없음") + @Test + void createMenuGroupNotExistException() { + //given + 맛초킹_세트.setMenuGroup(null); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); + } + + @DisplayName("메뉴 생성 예외 - 메뉴 상품 없음") + @Test + void createMenuProductsNotExistException() { + //given + 맛초킹_세트.setMenuProducts(null); + + given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 생성 예외 - 메뉴 상품 개수 미일치") + @Test + void createMenuProductsMismatchException() { + //given + 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹_1개, 맛초킹_1개, 콜라_1개)); + + given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 생성 예외 - 메뉴 상품 수량 부족") + @Test + void createMenuProductsLackQuantityException() { + 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_수량_오류)); + + given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); + given(productRepository.findById(맛초킹.getId())).willReturn(Optional.of(맛초킹)); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 생성 예외 - 상품들의 총 가격보다 높음") + @Test + void createPriceException() { + //given + 맛초킹_세트.setPrice(BigDecimal.valueOf(15_000L)); + + given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); + given(productRepository.findById(맛초킹.getId())).willReturn(Optional.of(맛초킹)); + given(productRepository.findById(콜라.getId())).willReturn(Optional.of(콜라)); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 생성 예외 - 이름에 비속어 포함") + @Test + void createNameException() { + //given + 맛초킹_세트.setName("비속어"); + + given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); + given(productRepository.findById(맛초킹.getId())).willReturn(Optional.of(맛초킹)); + given(productRepository.findById(콜라.getId())).willReturn(Optional.of(콜라)); + given(purgomalumClient.containsProfanity("비속어")).willReturn(true); + + //when + ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("메뉴 생성") + @Test + void create() { + //given + given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(뿌링클, 콜라)); + given(productRepository.findById(뿌링클.getId())).willReturn(Optional.of(뿌링클)); + given(productRepository.findById(콜라.getId())).willReturn(Optional.of(콜라)); + given(purgomalumClient.containsProfanity(anyString())).willReturn(false); + given(menuRepository.save(any(Menu.class))).willReturn(뿌링클_세트); + + //when + Menu menu = menuService.create(뿌링클_세트); + + //then + assertAll( + () -> assertThat(menu.getName()).isEqualTo("뿌링클 세트"), + () -> assertThat(menu.getMenuGroupId()).isEqualTo(세트메뉴.getId()), + () -> assertThat(menu.getMenuProducts()).hasSize(2), + () -> assertThat(menu.getPrice()).isEqualTo(뿌링클_세트.getPrice()), + () -> assertThat(menu.isDisplayed()).isTrue() + ); + } + + @DisplayName("가격 변경 예외 - 0원 미만") + @ParameterizedTest(name = "변경 가격: [{arguments}]") + @MethodSource("changePriceException") + void changePriceException(BigDecimal price) { + //given + 맛초킹_세트.setId(UUID.randomUUID()); + 맛초킹_세트.setPrice(price); + + //when + ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + private static Stream changePriceException() { + return Stream.of( + Arguments.of((BigDecimal) null), + Arguments.of(BigDecimal.valueOf(-1)) + ); + } + + @DisplayName("가격 변경 예외 - 상품들의 총 가격보다 높음") + @Test + void changePriceGreaterThanProductsPricesException() { + //given + 맛초킹_세트.setId(UUID.randomUUID()); + 맛초킹_세트.setPrice(BigDecimal.valueOf(15_000L)); + + given(menuRepository.findById(any(UUID.class))).willReturn(Optional.of(맛초킹_세트)); + + //when + ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 맛초킹_세트); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("가격 변경") + @Test + void changePrice() { + //given + Menu 변경할_가격 = new Menu(); + 변경할_가격.setPrice(BigDecimal.valueOf(10_500L)); + + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + + //when + Menu menu = menuService.changePrice(뿌링클_세트.getId(), 변경할_가격); + BigDecimal actual = menu.getPrice(); + + //then + assertThat(actual).isEqualTo(BigDecimal.valueOf(10_500L)); + } + + @DisplayName("진열 예외 - 상품들의 총 가격보다 높음") + @Test + void displayException() { + //given + 맛초킹_세트.setPrice(BigDecimal.valueOf(15_000L)); + + given(menuRepository.findById(any())).willReturn(Optional.of(맛초킹_세트)); + + //when + ThrowingCallable actual = () -> menuService.display(맛초킹_세트.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("진열") + @Test + void display() { + //given + 맛초킹_세트.setPrice(BigDecimal.valueOf(11_000L)); + + given(menuRepository.findById(any())).willReturn(Optional.of(맛초킹_세트)); + + //when + Menu menu = menuService.display(맛초킹_세트.getId()); + + //then + assertThat(menu.isDisplayed()).isTrue(); + } + + @DisplayName("진열 제외 - 등록된 메뉴만 진열 제외 가능") + @Test + void hideException() { + //given + given(menuRepository.findById(any())).willThrow(NoSuchElementException.class); + + //when + ThrowingCallable actual = () -> menuService.hide(뿌링클_세트.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); + } + + @DisplayName("진열 제외") + @Test + void hide() { + //given + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + + //when + Menu menu = menuService.hide(뿌링클_세트.getId()); + + //then + assertThat(menu.isDisplayed()).isFalse(); + } + + @DisplayName("모든 메뉴 조회") + @Test + void findALl() { + //given + given(menuRepository.findAll()).willReturn(Arrays.asList(뿌링클_세트, 맛초킹_세트)); + + //when + List actual = menuService.findAll(); + + //then + assertThat(actual).hasSize(2); + } + +} diff --git a/src/test/java/kitchenpos/application/ProductFixture.java b/src/test/java/kitchenpos/application/ProductFixture.java index 147d57665..a865df880 100644 --- a/src/test/java/kitchenpos/application/ProductFixture.java +++ b/src/test/java/kitchenpos/application/ProductFixture.java @@ -7,10 +7,12 @@ public class ProductFixture { public static final Product 뿌링클 = new Product(); + public static final Product 맛초킹 = new Product(); public static final Product 콜라 = new Product(); static { initialize(뿌링클, "뿌링클", 10_000L); + initialize(맛초킹, "맛초킹", 10_000L); initialize(콜라, "콜라", 2_000L); } From d94d60ce1653b2a9db3b97c60c9865d4933de2a9 Mon Sep 17 00:00:00 2001 From: yongju Date: Sun, 13 Mar 2022 15:47:22 +0900 Subject: [PATCH 08/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixture 객체를 수정하여 다른 테스트에 영향을 끼쳐 fixture 객체를 직접 수정하지 않도록 변경 --- src/test/java/kitchenpos/application/MenuServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index 3429619f6..af358df01 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -305,10 +305,10 @@ void hideException() { @Test void hide() { //given - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(맛초킹_세트)); //when - Menu menu = menuService.hide(뿌링클_세트.getId()); + Menu menu = menuService.hide(맛초킹_세트.getId()); //then assertThat(menu.isDisplayed()).isFalse(); From cb9e3ff27cd3dd8abddd7433fadb3c2c698e0485 Mon Sep 17 00:00:00 2001 From: yongju Date: Sun, 13 Mar 2022 15:47:42 +0900 Subject: [PATCH 09/40] =?UTF-8?q?test:=20=EC=83=81=ED=92=88=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixture 객체를 수정하여 다른 테스트에 영향을 끼쳐 fixture 객체를 직접 수정하지 않도록 변경 --- .../kitchenpos/application/ProductServiceTest.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/test/java/kitchenpos/application/ProductServiceTest.java b/src/test/java/kitchenpos/application/ProductServiceTest.java index a4f917809..69643981b 100644 --- a/src/test/java/kitchenpos/application/ProductServiceTest.java +++ b/src/test/java/kitchenpos/application/ProductServiceTest.java @@ -1,6 +1,7 @@ package kitchenpos.application; -import static kitchenpos.application.MenuFixture.뿌링클_세트; +import static kitchenpos.application.MenuProductFixture.뿌링클_1개; +import static kitchenpos.application.MenuProductFixture.콜라_1개; import static kitchenpos.application.ProductFixture.뿌링클; import static kitchenpos.application.ProductFixture.콜라; import static org.assertj.core.api.Assertions.assertThat; @@ -16,6 +17,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.Stream; +import kitchenpos.domain.Menu; import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; @@ -96,11 +98,15 @@ private static Stream constructorNameException() { @MethodSource("changePrice") void changePrice(long price, boolean expectedDisplayed) { //given - 뿌링클_세트.setDisplayed(true); + Menu menu = new Menu(); + menu.setDisplayed(true); + menu.setMenuProducts(Arrays.asList(뿌링클_1개, 콜라_1개)); + menu.setPrice(BigDecimal.valueOf(11_000L)); + Product 변경할_금액 = 상품_금액(price); given(productRepository.findById(any(UUID.class))).willReturn(Optional.of(뿌링클)); - given(menuRepository.findAllByProductId(any(UUID.class))).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findAllByProductId(any(UUID.class))).willReturn(Collections.singletonList(menu)); //when Product product = productService.changePrice(뿌링클.getId(), 변경할_금액); @@ -108,7 +114,7 @@ void changePrice(long price, boolean expectedDisplayed) { //then assertAll( () -> assertThat(product.getPrice()).isEqualTo(BigDecimal.valueOf(price)), - () -> assertThat(뿌링클_세트.isDisplayed()).isEqualTo(expectedDisplayed) + () -> assertThat(menu.isDisplayed()).isEqualTo(expectedDisplayed) ); } From efc2393842d8fed40c6ec24280cc5f1d0b67d350 Mon Sep 17 00:00:00 2001 From: yongju Date: Sun, 13 Mar 2022 15:50:42 +0900 Subject: [PATCH 10/40] =?UTF-8?q?test:=20=EC=A3=BC=EB=AC=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 41 +- .../kitchenpos/application/OrderService.java | 4 +- .../kitchenpos/application/MenuFixture.java | 20 +- .../kitchenpos/application/OrderFixture.java | 48 ++ .../application/OrderServiceTest.java | 566 ++++++++++++++++++ .../application/OrderTableFixture.java | 8 +- 6 files changed, 658 insertions(+), 29 deletions(-) create mode 100644 src/test/java/kitchenpos/application/OrderFixture.java create mode 100644 src/test/java/kitchenpos/application/OrderServiceTest.java diff --git a/README.md b/README.md index 0ff7bcd71..f37676c9d 100644 --- a/README.md +++ b/README.md @@ -38,31 +38,32 @@ - [x] 주문 완료된 식탁만 정리할 수 있다. - [x] 정리된 식탁은 기본 상태가 된다. - 주문 - - [ ] `주문 유형`, `주문 메뉴의 수량 및 가격`이 있다. - - [ ] 주문 유형은 `배달`, `포장`, `식당 내 식사`다. - - [ ] 배달 주문의 `상태`는 `대기`, `수락`, `조리 완료`, `배달 중`, `배달 완료`, `주문 완료` 순이다. - - [ ] 배달 주문은 `주소`가 있어야 한다. - - [ ] 포장 또는 식당 내 식사 주문의 `상태`는 `대기`, `수락`, `조리 완료`, `주문 완료` 순이다. - - [ ] 식당 내 식사는 `식탁`에 착석 후 가능하다. - - [ ] `주문 시간`은 실시간으로 지정한다. - - [ ] 등록된 메뉴가 진열되어야 한다. - - [ ] 1개 이상의 메뉴를 주문해야 한다. - - [ ] 지불한 금액이 주문한 메뉴의 총 금액과 일치해야 한다. - - [ ] 주문의 기본 상태는 대기다. + - [x] `주문 유형`, `주문 메뉴의 수량 및 가격`이 있다. + - [x] 주문 유형은 `배달`, `포장`, `식당 내 식사`다. + - [x] 배달 주문의 `상태`는 `대기`, `수락`, `조리 완료`, `배달 중`, `배달 완료`, `주문 완료` 순이다. + - [x] 배달 주문은 `주소`가 있어야 한다. + - [x] 포장 또는 식당 내 식사 주문의 `상태`는 `대기`, `수락`, `조리 완료`, `주문 완료` 순이다. + - [x] 식당 내 식사는 `식탁`에 착석 후 가능하다. + - [x] `주문 시간`은 실시간으로 지정한다. + - [x] 등록된 메뉴가 진열되어야 한다. + - [x] 1개 이상의 메뉴를 주문해야 한다. + - [x] 지불한 금액이 주문한 메뉴의 총 금액과 일치해야 한다. + - [x] 주문의 기본 상태는 대기다. + - [x] 식당 내 식사 주문은 음수를 활용해 주문을 취소할 수 있다. - 주문 수락 - - [ ] 대기 중인 주문만 수락할 수 있다. - - [ ] 배달 주문은 배달 요청한다. + - [x] 대기 중인 주문만 수락할 수 있다. + - [x] 배달 주문은 배달 요청한다. - 조리 완료 - - [ ] 수락된 주문만 조리 완료할 수 있다. + - [x] 수락된 주문만 조리 완료할 수 있다. - 배달 중 - - [ ] 배달 주문, 조리 완료 주문만 배달 시작할 수 있다. + - [x] 배달 주문, 조리 완료 주문만 배달 시작할 수 있다. - 배달 완료 - - [ ] 배달 중인 주문만 주문 완료할 수 있다. + - [x] 배달 중인 주문만 주문 완료할 수 있다. - 주문 완료 - - [ ] 배달 완료된 배달 주문을 주문 완료할 수 있다. - - [ ] 조리 완료된 포장 주문 또는 식당 내 식사 주문을 주문 완료할 수 있다. - - [ ] 식당 내 식사 주문이 완료되면 식탁을 정리한다. - - [ ] 모든 주문을 조회할 수 있다. + - [x] 배달 완료된 배달 주문을 주문 완료할 수 있다. + - [x] 조리 완료된 포장 주문 또는 식당 내 식사 주문을 주문 완료할 수 있다. + - [x] 식당 내 식사 주문이 완료되면 식탁을 정리한다. + - [x] 모든 주문을 조회할 수 있다. ## 용어 사전 diff --git a/src/main/java/kitchenpos/application/OrderService.java b/src/main/java/kitchenpos/application/OrderService.java index 9fb0d2d65..b2db0580d 100644 --- a/src/main/java/kitchenpos/application/OrderService.java +++ b/src/main/java/kitchenpos/application/OrderService.java @@ -102,9 +102,9 @@ public Order accept(final UUID orderId) { if (order.getType() == OrderType.DELIVERY) { BigDecimal sum = BigDecimal.ZERO; for (final OrderLineItem orderLineItem : order.getOrderLineItems()) { - sum = orderLineItem.getMenu() + sum = sum.add(orderLineItem.getMenu() .getPrice() - .multiply(BigDecimal.valueOf(orderLineItem.getQuantity())); + .multiply(BigDecimal.valueOf(orderLineItem.getQuantity()))); } kitchenridersClient.requestDelivery(orderId, sum, order.getDeliveryAddress()); } diff --git a/src/test/java/kitchenpos/application/MenuFixture.java b/src/test/java/kitchenpos/application/MenuFixture.java index 7f92b8482..167d70c22 100644 --- a/src/test/java/kitchenpos/application/MenuFixture.java +++ b/src/test/java/kitchenpos/application/MenuFixture.java @@ -1,24 +1,32 @@ package kitchenpos.application; import static kitchenpos.application.MenuGroupFixture.세트메뉴; +import static kitchenpos.application.MenuProductFixture.맛초킹_1개; import static kitchenpos.application.MenuProductFixture.뿌링클_1개; import static kitchenpos.application.MenuProductFixture.콜라_1개; import java.math.BigDecimal; import java.util.Arrays; import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuProduct; public class MenuFixture { public static final Menu 뿌링클_세트 = new Menu(); + public static final Menu 맛초킹_세트 = new Menu(); static { - 뿌링클_세트.setName("뿌링클 세트"); - 뿌링클_세트.setMenuGroup(세트메뉴); - 뿌링클_세트.setMenuGroupId(세트메뉴.getId()); - 뿌링클_세트.setMenuProducts(Arrays.asList(뿌링클_1개, 콜라_1개)); - 뿌링클_세트.setPrice(BigDecimal.valueOf(11_000L)); - 뿌링클_세트.setDisplayed(true); + initialize(뿌링클_세트, "뿌링클 세트", 뿌링클_1개); + initialize(맛초킹_세트, "맛초킹 세트", 맛초킹_1개); + } + + private static void initialize(Menu menu, String name, MenuProduct menuProduct) { + menu.setName(name); + menu.setMenuGroup(세트메뉴); + menu.setMenuGroupId(세트메뉴.getId()); + menu.setMenuProducts(Arrays.asList(menuProduct, 콜라_1개)); + menu.setPrice(BigDecimal.valueOf(11_000L)); + menu.setDisplayed(true); } } diff --git a/src/test/java/kitchenpos/application/OrderFixture.java b/src/test/java/kitchenpos/application/OrderFixture.java new file mode 100644 index 000000000..688163547 --- /dev/null +++ b/src/test/java/kitchenpos/application/OrderFixture.java @@ -0,0 +1,48 @@ +package kitchenpos.application; + +import static kitchenpos.application.MenuFixture.맛초킹_세트; +import static kitchenpos.application.MenuFixture.뿌링클_세트; +import static kitchenpos.application.OrderTableFixture.일번_테이블; + +import java.util.Arrays; +import java.util.Collections; +import java.util.UUID; +import kitchenpos.domain.Order; +import kitchenpos.domain.OrderLineItem; +import kitchenpos.domain.OrderType; + +public class OrderFixture { + + public static final Order 매장_주문 = new Order(); + public static final Order 포장_주문 = new Order(); + public static final Order 배달_주문 = new Order(); + + static { + 매장_주문.setId(UUID.randomUUID()); + 매장_주문.setType(OrderType.EAT_IN); + 매장_주문.setOrderLineItems(Collections.singletonList(주문_항목_뿌링클_세트())); + 매장_주문.setOrderTable(일번_테이블); + 매장_주문.setOrderTableId(일번_테이블.getId()); + + 포장_주문.setId(UUID.randomUUID()); + 포장_주문.setType(OrderType.TAKEOUT); + 포장_주문.setOrderLineItems(Collections.singletonList(주문_항목_맛초킹_세트())); + + 배달_주문.setId(UUID.randomUUID()); + 배달_주문.setType(OrderType.DELIVERY); + 배달_주문.setOrderLineItems(Arrays.asList(주문_항목_뿌링클_세트(), 주문_항목_맛초킹_세트())); + 배달_주문.setDeliveryAddress("ADDRESS"); + } + + private static OrderLineItem 주문_항목_뿌링클_세트() { + OrderLineItem orderLineItem = new OrderLineItem(); + orderLineItem.setMenu(뿌링클_세트); + return orderLineItem; + } + + private static OrderLineItem 주문_항목_맛초킹_세트() { + OrderLineItem orderLineItem = new OrderLineItem(); + orderLineItem.setMenu(맛초킹_세트); + return orderLineItem; + } +} diff --git a/src/test/java/kitchenpos/application/OrderServiceTest.java b/src/test/java/kitchenpos/application/OrderServiceTest.java new file mode 100644 index 000000000..d0b23d43e --- /dev/null +++ b/src/test/java/kitchenpos/application/OrderServiceTest.java @@ -0,0 +1,566 @@ +package kitchenpos.application; + +import static kitchenpos.application.MenuFixture.뿌링클_세트; +import static kitchenpos.application.OrderFixture.매장_주문; +import static kitchenpos.application.OrderFixture.배달_주문; +import static kitchenpos.application.OrderFixture.포장_주문; +import static kitchenpos.application.OrderTableFixture.일번_테이블; +import static kitchenpos.application.OrderTableFixture.착석_테이블; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; +import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuRepository; +import kitchenpos.domain.Order; +import kitchenpos.domain.OrderLineItem; +import kitchenpos.domain.OrderRepository; +import kitchenpos.domain.OrderStatus; +import kitchenpos.domain.OrderTableRepository; +import kitchenpos.domain.OrderType; +import kitchenpos.infra.KitchenridersClient; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayName("주문") +@ExtendWith(MockitoExtension.class) +class OrderServiceTest { + + @Mock + private OrderRepository orderRepository; + @Mock + private MenuRepository menuRepository; + @Mock + private OrderTableRepository orderTableRepository; + @Mock + private KitchenridersClient kitchenridersClient; + + @InjectMocks + private OrderService orderService; + + private Order 신규_주문; + + @BeforeEach + void setUp() { + 신규_주문 = new Order(); + 신규_주문.setId(UUID.randomUUID()); + 신규_주문.setType(OrderType.DELIVERY); + OrderLineItem orderLineItem = new OrderLineItem(); + orderLineItem.setMenu(뿌링클_세트); + orderLineItem.setMenuId(뿌링클_세트.getId()); + orderLineItem.setQuantity(1L); + orderLineItem.setPrice(뿌링클_세트.getPrice()); + 신규_주문.setOrderLineItems(Collections.singletonList(orderLineItem)); + 신규_주문.setDeliveryAddress("배달주소"); + 신규_주문.setOrderTableId(일번_테이블.getId()); + 신규_주문.setOrderTable(일번_테이블); + 신규_주문.setStatus(OrderStatus.WAITING); + 신규_주문.setOrderDateTime(LocalDateTime.now()); + } + + @DisplayName("주문 예외 - 주문 유형 없음") + @Test + void createOrderTypeException() { + //given + 신규_주문.setType(null); + + //when + ThrowingCallable actual = () -> orderService.create(new Order()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + + + @DisplayName("주문 예외 - 주문 메뉴 없음") + @ParameterizedTest(name = "주문 메뉴: [{arguments}]") + @NullAndEmptySource + void createOrderHasNoMenuException(List orderLineItems) { + //given + 신규_주문.setOrderLineItems(orderLineItems); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("주문 예외 - 등록되지 않은 메뉴 주문") + @Test + void createOrderInvalidMenuException() { + //given + given(menuRepository.findAllByIdIn(anyList())).willReturn(new ArrayList<>()); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("주문 예외 - 포장 또는 배달 메뉴 수량 미달") + @ParameterizedTest(name = "메뉴 유형: [{arguments}]") + @EnumSource(value = OrderType.class, names = {"DELIVERY", "TAKEOUT"}) + void createOrderInvalidQuantityException(OrderType orderType) { + //given + 신규_주문.setType(orderType); + OrderLineItem 모자란_수량 = new OrderLineItem(); + 모자란_수량.setQuantity(-1L); + 신규_주문.setOrderLineItems(Collections.singletonList(모자란_수량)); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(new ArrayList<>()); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("주문 예외 - 진열되지 않은 메뉴 주문") + @Test + void createOrderNotDisplayedMenuException() { + //given + Menu 진열되지_않은_메뉴 = new Menu(); + 진열되지_않은_메뉴.setDisplayed(false); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(진열되지_않은_메뉴)); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("주문 예외 - 가격 불일치") + @Test + void createOrderMismatchPriceException() { + //given + OrderLineItem 모자란_금액 = new OrderLineItem(); + 모자란_금액.setPrice(BigDecimal.valueOf(10_000L)); + + 신규_주문.setOrderLineItems(Collections.singletonList(모자란_금액)); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("주문 예외 - 배달 주문 시 배달 주소 없음") + @ParameterizedTest(name = "배달 주소: [{arguments}]") + @NullAndEmptySource + void createDeliveryOrderHasNoAddressException(String deliveryAddress) { + //given + 신규_주문.setDeliveryAddress(deliveryAddress); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("주문 예외 - 식당 내 주문 시 착석하지 않음") + @Test + void createEatInException() { + //given + 신규_주문.setType(OrderType.EAT_IN); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + + //when + ThrowingCallable actual = () -> orderService.create(신규_주문); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("매장 주문 성공") + @Test + void createOrderEatIn() { + //given + 신규_주문.setType(OrderType.EAT_IN); + 신규_주문.setOrderTableId(착석_테이블.getId()); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(착석_테이블)); + given(orderRepository.save(any(Order.class))).willReturn(신규_주문); + + //when + Order order = orderService.create(신규_주문); + + //then + assertAll( + () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), + () -> assertThat(order.getType()).isEqualTo(OrderType.EAT_IN), + () -> assertThat(order.getOrderDateTime()).isEqualTo(신규_주문.getOrderDateTime()), + () -> assertThat(order.getOrderTableId()).isEqualTo(착석_테이블.getId()) + ); + } + + @DisplayName("포장 주문 성공") + @Test + void createOrderTakeout() { + //given + 신규_주문.setType(OrderType.TAKEOUT); + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + given(orderRepository.save(any(Order.class))).willReturn(신규_주문); + + //when + Order order = orderService.create(신규_주문); + + //then + assertAll( + () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), + () -> assertThat(order.getType()).isEqualTo(OrderType.TAKEOUT), + () -> assertThat(order.getOrderDateTime()).isEqualTo(신규_주문.getOrderDateTime()) + ); + } + + @DisplayName("배달 주문 성공") + @Test + void createOrderDelivery() { + //given + + given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); + given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + given(orderRepository.save(any(Order.class))).willReturn(신규_주문); + + //when + Order order = orderService.create(신규_주문); + + //then + assertAll( + () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), + () -> assertThat(order.getType()).isEqualTo(OrderType.DELIVERY), + () -> assertThat(order.getOrderDateTime()).isEqualTo(신규_주문.getOrderDateTime()) + ); + } + + @DisplayName("주문 수락 예외 - 대기중인 주문만 수락 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"ACCEPTED", "SERVED", "DELIVERING", "DELIVERED", "COMPLETED"}) + void accept(OrderStatus orderStatus) { + //given + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.accept(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("배달 주문 수락") + @Test + void acceptOrderDelivery() { + //given + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.accept(신규_주문.getId()); + + //then + assertAll( + () -> assertThat(actual.getStatus()).isEqualTo(OrderStatus.ACCEPTED), + () -> verify(kitchenridersClient, atLeastOnce()).requestDelivery(any(), any(), any()) + ); + } + + @DisplayName("주문 수락") + @ParameterizedTest(name = "주문 유형: [{arguments}]") + @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) + void accept(OrderType orderType) { + //given + 신규_주문.setType(orderType); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.accept(신규_주문.getId()); + + //then + assertThat(actual.getStatus()).isEqualTo(OrderStatus.ACCEPTED); + } + + @DisplayName("조리 완료 예외 - 수락된 주문만 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"WAITING", "SERVED", "DELIVERING", "DELIVERED", "COMPLETED"}) + void serveException(OrderStatus orderStatus) { + //given + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.serve(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("조리 완료") + @Test + void serve() { + //given + 신규_주문.setStatus(OrderStatus.ACCEPTED); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.serve(신규_주문.getId()); + + //then + assertThat(actual.getStatus()).isEqualTo(OrderStatus.SERVED); + } + + @DisplayName("배달 중 예외 - 배달 주문만 가능") + @ParameterizedTest(name = "주문 유형: [{arguments}]") + @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) + void startDeliveryOrderTypeException(OrderType orderType) { + //given + 신규_주문.setType(orderType); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.startDelivery(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("배달 중 예외 - 조리완료된 주문만 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERING", "DELIVERED", "COMPLETED"}) + void startDeliveryOrderStatusException(OrderStatus orderStatus) { + //given + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.startDelivery(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("배달 중") + @Test + void startDelivery() { + //given + 신규_주문.setType(OrderType.DELIVERY); + 신규_주문.setStatus(OrderStatus.SERVED); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.startDelivery(신규_주문.getId()); + + //then + assertThat(actual.getStatus()).isEqualTo(OrderStatus.DELIVERING); + } + + @DisplayName("배달 완료 예외 - 배달중인 주문만 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERED", "COMPLETED"}) + void completeDeliveryOrderStatusException(OrderStatus orderStatus) { + //given + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.completeDelivery(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("배달 완료") + @Test + void completeDelivery() { + //given + 신규_주문.setType(OrderType.DELIVERY); + 신규_주문.setStatus(OrderStatus.DELIVERING); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.completeDelivery(신규_주문.getId()); + + //then + assertThat(actual.getStatus()).isEqualTo(OrderStatus.DELIVERED); + } + + @DisplayName("배달 주문 완료 예외 - 배달 완료 주문만 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERING", "COMPLETED"}) + void completeDeliveryStatusException(OrderStatus orderStatus) { + //given + 신규_주문.setType(OrderType.DELIVERY); + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.complete(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("배달 주문 완료") + @Test + void completeDeliveryOrder() { + //given + 신규_주문.setType(OrderType.DELIVERY); + 신규_주문.setStatus(OrderStatus.DELIVERED); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.complete(신규_주문.getId()); + + //then + assertThat(actual.getStatus()).isEqualTo(OrderStatus.COMPLETED); + } + + @DisplayName("포장 주문 완료 예외 - 조리완료된 주문만 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) + void completeTakeoutOrderStatusException(OrderStatus orderStatus) { + //given + 신규_주문.setType(OrderType.TAKEOUT); + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.complete(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("매장 주문 완료 예외 - 조리완료된 주문만 가능") + @ParameterizedTest(name = "주문 상태: [{arguments}]") + @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) + void completeEatInStatusException(OrderStatus orderStatus) { + //given + 신규_주문.setType(OrderType.EAT_IN); + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + ThrowingCallable actual = () -> orderService.complete(신규_주문.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("주문 완료 - 포장, 배달") + @ParameterizedTest(name = "주문 유형: [{0}], 주문 상태: [{1}]") + @MethodSource("completeTakeoutOrDelivery") + void completeTakeoutOrDeliveryOrder(OrderType orderType, OrderStatus orderStatus) { + //given + 신규_주문.setType(orderType); + 신규_주문.setStatus(orderStatus); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + + //when + Order actual = orderService.complete(신규_주문.getId()); + + //then + assertThat(actual.getStatus()).isEqualTo(OrderStatus.COMPLETED); + } + + private static Stream completeTakeoutOrDelivery() { + return Stream.of( + Arguments.of(OrderType.DELIVERY, OrderStatus.DELIVERED), + Arguments.of(OrderType.TAKEOUT, OrderStatus.SERVED) + ); + } + + @DisplayName("매장 주문 완료") + @Test + void completeEatInOrder() { + //given + 신규_주문.setType(OrderType.EAT_IN); + 신규_주문.setStatus(OrderStatus.SERVED); + + given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + given(orderRepository.existsByOrderTableAndStatusNot(any(), any())).willReturn(true); + + //when + Order actual = orderService.complete(신규_주문.getId()); + + //then + assertAll( + () -> assertThat(actual.getStatus()).isEqualTo(OrderStatus.COMPLETED), + () -> assertThat(actual.getOrderTable().isEmpty()).isTrue(), + () -> assertThat(actual.getOrderTable().getNumberOfGuests()).isZero() + ); + } + + @DisplayName("모든 주문 조회") + @Test + void findAll() { + //given + given(orderRepository.findAll()).willReturn(Arrays.asList(배달_주문, 포장_주문, 매장_주문)); + + //when + List actual = orderService.findAll(); + + //then + assertThat(actual).hasSize(3); + } + +} diff --git a/src/test/java/kitchenpos/application/OrderTableFixture.java b/src/test/java/kitchenpos/application/OrderTableFixture.java index e8660f5cf..73a82b293 100644 --- a/src/test/java/kitchenpos/application/OrderTableFixture.java +++ b/src/test/java/kitchenpos/application/OrderTableFixture.java @@ -7,16 +7,22 @@ public class OrderTableFixture { public static final OrderTable 일번_테이블 = new OrderTable(); public static final OrderTable 삼번_테이블 = new OrderTable(); + public static final OrderTable 착석_테이블 = new OrderTable(); static { initialize(일번_테이블, "1번"); initialize(삼번_테이블, "3번"); + initialize(착석_테이블, "5번", false); } private static void initialize(OrderTable orderTable, String name) { + initialize(orderTable, name, true); + } + + private static void initialize(OrderTable orderTable, String name, boolean empty) { orderTable.setId(UUID.randomUUID()); orderTable.setName(name); orderTable.setNumberOfGuests(0); - orderTable.setEmpty(true); + orderTable.setEmpty(empty); } } From 3f02d9a0d310b0f2abb0891eda7a57ea15b37a4a Mon Sep 17 00:00:00 2001 From: yongju Date: Sun, 13 Mar 2022 15:54:11 +0900 Subject: [PATCH 11/40] =?UTF-8?q?chore:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/FakePurgomalumClient.java | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/test/java/kitchenpos/application/FakePurgomalumClient.java diff --git a/src/test/java/kitchenpos/application/FakePurgomalumClient.java b/src/test/java/kitchenpos/application/FakePurgomalumClient.java deleted file mode 100644 index d7b16db24..000000000 --- a/src/test/java/kitchenpos/application/FakePurgomalumClient.java +++ /dev/null @@ -1,16 +0,0 @@ -package kitchenpos.application; - -import kitchenpos.infra.PurgomalumClient; -import org.springframework.boot.web.client.RestTemplateBuilder; - -public class FakePurgomalumClient extends PurgomalumClient { - - public FakePurgomalumClient(RestTemplateBuilder restTemplateBuilder) { - super(new RestTemplateBuilder()); - } - - @Override - public boolean containsProfanity(String text) { - return "비속어".equals(text); - } -} From 306fde12043345b187e1c359724d00817675f46e Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 16 Mar 2022 19:46:36 +0900 Subject: [PATCH 12/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mock 대신 fake 객체 활용 --- .../domain/MenuGroupRepository.java | 16 +++++++- .../InMemoryMenuGroupRepository.java | 31 ++++++++++++++++ .../application/MenuGroupServiceTest.java | 37 ++++++++++--------- .../ui/MenuGroupRestControllerTest.java | 37 ++++++++++++++----- 4 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java diff --git a/src/main/java/kitchenpos/domain/MenuGroupRepository.java b/src/main/java/kitchenpos/domain/MenuGroupRepository.java index 13fa29eda..d6d238e07 100644 --- a/src/main/java/kitchenpos/domain/MenuGroupRepository.java +++ b/src/main/java/kitchenpos/domain/MenuGroupRepository.java @@ -1,8 +1,20 @@ package kitchenpos.domain; -import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; +import java.util.Optional; import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MenuGroupRepository { + + MenuGroup save(MenuGroup menuGroup); + + List findAll(); + + Optional findById(UUID menuGroupId); +} + +interface JpaMenuGroupRepository extends MenuGroupRepository, JpaRepository { -public interface MenuGroupRepository extends JpaRepository { } diff --git a/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java b/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java new file mode 100644 index 000000000..881841e71 --- /dev/null +++ b/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java @@ -0,0 +1,31 @@ +package kitchenpos.application; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import kitchenpos.domain.MenuGroup; +import kitchenpos.domain.MenuGroupRepository; + +public class InMemoryMenuGroupRepository implements MenuGroupRepository { + + private final Map menuGroups = new HashMap<>(); + + @Override + public MenuGroup save(MenuGroup menuGroup) { + menuGroups.put(menuGroup.getId(), menuGroup); + return menuGroup; + } + + @Override + public List findAll() { + return new ArrayList<>(menuGroups.values()); + } + + @Override + public Optional findById(UUID menuGroupId) { + return Optional.ofNullable(menuGroups.get(menuGroupId)); + } +} diff --git a/src/test/java/kitchenpos/application/MenuGroupServiceTest.java b/src/test/java/kitchenpos/application/MenuGroupServiceTest.java index 48d389c56..8e824aba8 100644 --- a/src/test/java/kitchenpos/application/MenuGroupServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuGroupServiceTest.java @@ -1,44 +1,38 @@ package kitchenpos.application; -import static kitchenpos.application.MenuGroupFixture.메뉴판; import static kitchenpos.application.MenuGroupFixture.세트메뉴; import static kitchenpos.application.MenuGroupFixture.추천메뉴; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; import java.util.List; import kitchenpos.domain.MenuGroup; import kitchenpos.domain.MenuGroupRepository; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; @DisplayName("메뉴 그룹") -@ExtendWith(MockitoExtension.class) class MenuGroupServiceTest { - @Mock - private MenuGroupRepository menuGroupRepository; - - @InjectMocks + private final MenuGroupRepository menuGroupRepository = new InMemoryMenuGroupRepository(); private MenuGroupService menuGroupService; + @BeforeEach + void setUp() { + menuGroupService = new MenuGroupService(menuGroupRepository); + } + @DisplayName("이름이 없으면 예외 발생") @ParameterizedTest(name = "이름: [{arguments}]") @NullAndEmptySource void createNonameException(String name) { //given - MenuGroup 이름_없는_메뉴_그룹 = new MenuGroup(); - 이름_없는_메뉴_그룹.setName(name); + MenuGroup 이름_없는_메뉴_그룹 = 메뉴_그룹_생성(name); //when ThrowingCallable actual = () -> menuGroupService.create(이름_없는_메뉴_그룹); @@ -51,10 +45,10 @@ void createNonameException(String name) { @Test void create() { //given - given(menuGroupRepository.save(any(MenuGroup.class))).willReturn(세트메뉴); + MenuGroup 신규_메뉴_그룹 = 메뉴_그룹_생성(세트메뉴.getName()); //when - MenuGroup menuGroup = menuGroupService.create(세트메뉴); + MenuGroup menuGroup = menuGroupService.create(신규_메뉴_그룹); //then assertAll( @@ -67,7 +61,8 @@ void create() { @Test void findAll() { //given - given(menuGroupRepository.findAll()).willReturn(메뉴판); + menuGroupRepository.save(추천메뉴); + menuGroupRepository.save(세트메뉴); //when List menuGroups = menuGroupService.findAll(); @@ -76,7 +71,13 @@ void findAll() { assertAll( () -> assertThat(menuGroups).hasSize(2), () -> assertThat(menuGroups).extracting("name") - .containsExactly(세트메뉴.getName(), 추천메뉴.getName()) + .contains(세트메뉴.getName(), 추천메뉴.getName()) ); } + + private MenuGroup 메뉴_그룹_생성(String name) { + MenuGroup menuGroup = new MenuGroup(); + menuGroup.setName(name); + return menuGroup; + } } diff --git a/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java b/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java index 46dcb97dc..0cdc26860 100644 --- a/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java +++ b/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java @@ -20,10 +20,14 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +@DisplayName("메뉴 그룹 관리") @WebMvcTest(MenuGroupRestController.class) class MenuGroupRestControllerTest { + private static final String MENU_GROUPS_URI = "/api/menu-groups"; + @Autowired private MockMvc webMvc; @@ -36,17 +40,16 @@ class MenuGroupRestControllerTest { @DisplayName("메뉴그룹 생성") @Test void create() throws Exception { - //when + //given String body = objectMapper.writeValueAsString(세트메뉴); - //when given(menuGroupService.create(any())).willReturn(세트메뉴); + //when + ResultActions resultActions = 그룹_생성_요청(body); + //then - webMvc.perform(post("/api/menu-groups") - .contentType(MediaType.APPLICATION_JSON) - .content(body)) - .andDo(print()) + resultActions .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").isNotEmpty()) .andExpect(jsonPath("$.name").value(세트메뉴.getName())); @@ -55,15 +58,29 @@ void create() throws Exception { @DisplayName("메뉴그룹 조회") @Test void findAll() throws Exception { - //when + //given given(menuGroupService.findAll()).willReturn(메뉴판); + //when + ResultActions resultActions = 그룹_조회_요청(); + //then - webMvc.perform(get("/api/menu-groups") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) + resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$[0].name").value(세트메뉴.getName())) .andExpect(jsonPath("$[1].name").value(추천메뉴.getName())); } + + private ResultActions 그룹_생성_요청(String body) throws Exception { + return webMvc.perform(post(MENU_GROUPS_URI) + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andDo(print()); + } + + private ResultActions 그룹_조회_요청() throws Exception { + return webMvc.perform(get(MENU_GROUPS_URI) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()); + } } From 2c13ca516558145cbea02be39776b5dc298c7d55 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 16 Mar 2022 22:21:06 +0900 Subject: [PATCH 13/40] =?UTF-8?q?test:=20=EC=83=81=ED=92=88=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mock 대신 fake 객체 활용 DisplayName을 요구사항과 일치하도록 변경 --- .../application/ProductService.java | 8 +- .../kitchenpos/domain/MenuRepository.java | 14 +- .../kitchenpos/domain/ProductRepository.java | 13 +- .../kitchenpos/infra/ProfanityClient.java | 7 + .../kitchenpos/infra/PurgomalumClient.java | 4 +- .../application/FakeProfanityClient.java | 22 +++ .../application/InMemoryMenuRepository.java | 52 +++++++ .../InMemoryProductRepository.java | 40 ++++++ .../application/ProductServiceTest.java | 136 ++++++++---------- 9 files changed, 215 insertions(+), 81 deletions(-) create mode 100644 src/main/java/kitchenpos/infra/ProfanityClient.java create mode 100644 src/test/java/kitchenpos/application/FakeProfanityClient.java create mode 100644 src/test/java/kitchenpos/application/InMemoryMenuRepository.java create mode 100644 src/test/java/kitchenpos/application/InMemoryProductRepository.java diff --git a/src/main/java/kitchenpos/application/ProductService.java b/src/main/java/kitchenpos/application/ProductService.java index 3d86f06d5..37b63aeb3 100644 --- a/src/main/java/kitchenpos/application/ProductService.java +++ b/src/main/java/kitchenpos/application/ProductService.java @@ -1,7 +1,7 @@ package kitchenpos.application; import kitchenpos.domain.*; -import kitchenpos.infra.PurgomalumClient; +import kitchenpos.infra.ProfanityClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -15,12 +15,12 @@ public class ProductService { private final ProductRepository productRepository; private final MenuRepository menuRepository; - private final PurgomalumClient purgomalumClient; + private final ProfanityClient purgomalumClient; public ProductService( final ProductRepository productRepository, final MenuRepository menuRepository, - final PurgomalumClient purgomalumClient + final ProfanityClient purgomalumClient ) { this.productRepository = productRepository; this.menuRepository = menuRepository; @@ -48,7 +48,7 @@ public Product create(final Product request) { public Product changePrice(final UUID productId, final Product request) { final BigDecimal price = request.getPrice(); if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("0원 미만의 가격으로 등록할 수 없습니다."); } final Product product = productRepository.findById(productId) .orElseThrow(NoSuchElementException::new); diff --git a/src/main/java/kitchenpos/domain/MenuRepository.java b/src/main/java/kitchenpos/domain/MenuRepository.java index 544493ac7..22bec5b43 100644 --- a/src/main/java/kitchenpos/domain/MenuRepository.java +++ b/src/main/java/kitchenpos/domain/MenuRepository.java @@ -1,5 +1,6 @@ package kitchenpos.domain; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -7,9 +8,20 @@ import java.util.List; import java.util.UUID; -public interface MenuRepository extends JpaRepository { +public interface MenuRepository { List findAllByIdIn(List ids); @Query("select m from Menu m, MenuProduct mp where mp.product.id = :productId") List findAllByProductId(@Param("productId") UUID productId); + + Optional findById(UUID menuId); + + Menu save(Menu menu); + + List findAll(); + +} + +interface JpaMenuRepository extends MenuRepository, JpaRepository { + } diff --git a/src/main/java/kitchenpos/domain/ProductRepository.java b/src/main/java/kitchenpos/domain/ProductRepository.java index b19420297..dad74fd84 100644 --- a/src/main/java/kitchenpos/domain/ProductRepository.java +++ b/src/main/java/kitchenpos/domain/ProductRepository.java @@ -1,10 +1,21 @@ package kitchenpos.domain; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; import java.util.UUID; -public interface ProductRepository extends JpaRepository { +public interface ProductRepository { List findAllByIdIn(List ids); + + Optional findById(UUID productId); + + Product save(Product product); + + List findAll(); +} + +interface JpaProductRepository extends ProductRepository, JpaRepository { + } diff --git a/src/main/java/kitchenpos/infra/ProfanityClient.java b/src/main/java/kitchenpos/infra/ProfanityClient.java new file mode 100644 index 000000000..38ed04476 --- /dev/null +++ b/src/main/java/kitchenpos/infra/ProfanityClient.java @@ -0,0 +1,7 @@ +package kitchenpos.infra; + +public interface ProfanityClient { + + boolean containsProfanity(final String text); + +} diff --git a/src/main/java/kitchenpos/infra/PurgomalumClient.java b/src/main/java/kitchenpos/infra/PurgomalumClient.java index 2ed085bed..70655bd29 100644 --- a/src/main/java/kitchenpos/infra/PurgomalumClient.java +++ b/src/main/java/kitchenpos/infra/PurgomalumClient.java @@ -8,13 +8,15 @@ import java.net.URI; @Component -public class PurgomalumClient { +public class PurgomalumClient implements ProfanityClient { + private final RestTemplate restTemplate; public PurgomalumClient(final RestTemplateBuilder restTemplateBuilder) { this.restTemplate = restTemplateBuilder.build(); } + @Override public boolean containsProfanity(final String text) { final URI url = UriComponentsBuilder.fromUriString("https://www.purgomalum.com/service/containsprofanity") .queryParam("text", text) diff --git a/src/test/java/kitchenpos/application/FakeProfanityClient.java b/src/test/java/kitchenpos/application/FakeProfanityClient.java new file mode 100644 index 000000000..33642622f --- /dev/null +++ b/src/test/java/kitchenpos/application/FakeProfanityClient.java @@ -0,0 +1,22 @@ +package kitchenpos.application; + +import java.util.HashSet; +import java.util.Set; +import kitchenpos.infra.ProfanityClient; + +public class FakeProfanityClient implements ProfanityClient { + + private static final Set profanityDictionary = new HashSet<>(); + + static { + profanityDictionary.add("욕"); + profanityDictionary.add("비속어"); + profanityDictionary.add("나쁜말"); + } + + @Override + public boolean containsProfanity(final String text) { + return profanityDictionary.stream() + .anyMatch(text::contains); + } +} diff --git a/src/test/java/kitchenpos/application/InMemoryMenuRepository.java b/src/test/java/kitchenpos/application/InMemoryMenuRepository.java new file mode 100644 index 000000000..8b8521b9d --- /dev/null +++ b/src/test/java/kitchenpos/application/InMemoryMenuRepository.java @@ -0,0 +1,52 @@ +package kitchenpos.application; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuRepository; + +public class InMemoryMenuRepository implements MenuRepository { + + private final Map menus = new HashMap<>(); + + @Override + public List findAllByIdIn(List ids) { + return menus.values().stream() + .filter(menu -> ids.contains(menu.getId())) + .collect(Collectors.toList()); + } + + @Override + public List findAllByProductId(UUID productId) { + return menus.values().stream() + .filter( + menu -> menu.getMenuProducts() + .stream() + .anyMatch(menuProduct -> Objects.equals(menuProduct.getProductId(), productId)) + ) + .collect(Collectors.toList()); + } + + @Override + public Optional findById(UUID menuId) { + return Optional.ofNullable(menus.get(menuId)); + } + + @Override + public Menu save(Menu menu) { + menu.setId(UUID.randomUUID()); + menus.put(menu.getId(), menu); + return menu; + } + + @Override + public List findAll() { + return new ArrayList<>(menus.values()); + } +} diff --git a/src/test/java/kitchenpos/application/InMemoryProductRepository.java b/src/test/java/kitchenpos/application/InMemoryProductRepository.java new file mode 100644 index 000000000..eedb2558c --- /dev/null +++ b/src/test/java/kitchenpos/application/InMemoryProductRepository.java @@ -0,0 +1,40 @@ +package kitchenpos.application; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import kitchenpos.domain.Product; +import kitchenpos.domain.ProductRepository; + +public class InMemoryProductRepository implements ProductRepository { + + private final Map products = new HashMap<>(); + + @Override + public List findAllByIdIn(List ids) { + return products.values().stream() + .filter(product -> ids.contains(product.getId())) + .collect(Collectors.toList()); + } + + @Override + public Optional findById(UUID productId) { + return Optional.ofNullable(products.get(productId)); + } + + @Override + public Product save(Product product) { + product.setId(UUID.randomUUID()); + products.put(product.getId(), product); + return product; + } + + @Override + public List findAll() { + return new ArrayList<>(products.values()); + } +} diff --git a/src/test/java/kitchenpos/application/ProductServiceTest.java b/src/test/java/kitchenpos/application/ProductServiceTest.java index 69643981b..ba591d0ec 100644 --- a/src/test/java/kitchenpos/application/ProductServiceTest.java +++ b/src/test/java/kitchenpos/application/ProductServiceTest.java @@ -7,52 +7,47 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; import java.math.BigDecimal; import java.util.Arrays; -import java.util.Collections; import java.util.List; -import java.util.Optional; +import java.util.NoSuchElementException; import java.util.UUID; -import java.util.stream.Stream; import kitchenpos.domain.Menu; import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; -import kitchenpos.infra.PurgomalumClient; +import kitchenpos.infra.ProfanityClient; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@DisplayName("상품") -@ExtendWith(MockitoExtension.class) +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +@DisplayName("상품 관리") class ProductServiceTest { - @Mock - private ProductRepository productRepository; - @Mock - private MenuRepository menuRepository; - @Mock(lenient = true) - private PurgomalumClient purgomalumClient; + private final ProductRepository productRepository = new InMemoryProductRepository(); + private final MenuRepository menuRepository = new InMemoryMenuRepository(); + private final ProfanityClient profanityClient = new FakeProfanityClient(); - @InjectMocks private ProductService productService; - @DisplayName("상품 가격 0원 이하 불가") + @BeforeEach + void setUp() { + productService = new ProductService(productRepository, menuRepository, profanityClient); + } + + @DisplayName("가격은 0원 이상이어야 한다.") @ParameterizedTest(name = "상품금액: [{arguments}]") - @MethodSource("priceException") + @ValueSource(strings = {"-1"}) + @NullSource void createPriceException(BigDecimal price) { //given - Product product = 상품_금액(price); + Product product = 상품_생성(price); //when ThrowingCallable actual = () -> productService.create(product); @@ -61,23 +56,13 @@ void createPriceException(BigDecimal price) { assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - private static Stream priceException() { - return Stream.of( - Arguments.of((BigDecimal) null), - Arguments.of(BigDecimal.valueOf(-1)) - ); - } - - @DisplayName("상품의 이름에 비속어 사용 불가") + @DisplayName("이름에 비속어를 사용할 수 없다.") @ParameterizedTest(name = "상품 이름: [{arguments}]") - @MethodSource("constructorNameException") + @ValueSource(strings = {"비속어", "욕"}) + @NullSource void createNameException(String name) { //given - Product product = new Product(); - product.setPrice(BigDecimal.valueOf(10_000L)); - product.setName(name); - - given(purgomalumClient.containsProfanity("비속어")).willReturn(true); + Product product = 상품_생성(name); //when ThrowingCallable actual = () -> productService.create(product); @@ -86,27 +71,23 @@ void createNameException(String name) { assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - private static Stream constructorNameException() { - return Stream.of( - Arguments.of((String) null), - Arguments.of("비속어") - ); - } - - @DisplayName("가격 변경") + @DisplayName("가격을 변경할 수 있다. 가격이 해당 상품을 포함하는 메뉴의 가격보다 크면 메뉴를 진열하지 않는다.") @ParameterizedTest(name = "변경할 가격: [{0}], 진열 여부: [{1}]") - @MethodSource("changePrice") + @CsvSource(value = { + "8000, false", + "15000, true" + }) void changePrice(long price, boolean expectedDisplayed) { //given + productRepository.save(뿌링클); + Menu menu = new Menu(); menu.setDisplayed(true); menu.setMenuProducts(Arrays.asList(뿌링클_1개, 콜라_1개)); menu.setPrice(BigDecimal.valueOf(11_000L)); + menuRepository.save(menu); - Product 변경할_금액 = 상품_금액(price); - - given(productRepository.findById(any(UUID.class))).willReturn(Optional.of(뿌링클)); - given(menuRepository.findAllByProductId(any(UUID.class))).willReturn(Collections.singletonList(menu)); + Product 변경할_금액 = 상품_생성(price); //when Product product = productService.changePrice(뿌링클.getId(), 변경할_금액); @@ -118,64 +99,71 @@ void changePrice(long price, boolean expectedDisplayed) { ); } - private static Stream changePrice() { - return Stream.of( - Arguments.of(8_000L, false), - Arguments.of(15_000L, true) - ); - } - - @DisplayName("가격 변경 예외") + @DisplayName("0원 미만의 가격으로 변경할 수 없다.") @ParameterizedTest(name = "변경할 가격: [{arguments}]") - @MethodSource("priceException") + @ValueSource(strings = {"-1"}) + @NullSource void changePriceException(BigDecimal price) { //given - Product 뿌링클_가격_변경 = 상품_금액(price); + Product 사이다 = 상품_생성(2_000L); + productRepository.save(사이다); + + Product 사이다_가격_변경 = 상품_생성(price); //when - ThrowingCallable actual = () -> productService.changePrice(뿌링클.getId(), 뿌링클_가격_변경); + ThrowingCallable actual = () -> productService.changePrice(사이다.getId(), 사이다_가격_변경); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("등록되지 않은 상품의 가격 변경 예외") + @DisplayName("등록되지 않은 상품은 가격을 변경할 수 없다.") @Test void changePriceNotExistProductException() { //given - Product 뿌링클_가격_변경 = 상품_금액(10_000L); + UUID 등록되지_않은_상품_ID = UUID.randomUUID(); - given(productRepository.findById(any(UUID.class))).willThrow(IllegalArgumentException.class); + Product 뿌링클_가격_변경 = 상품_생성(10_000L); //when - ThrowingCallable actual = () -> productService.changePrice(뿌링클.getId(), 뿌링클_가격_변경); + ThrowingCallable actual = () -> productService.changePrice(등록되지_않은_상품_ID, 뿌링클_가격_변경); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); } - @DisplayName("모든 상품 조회") + @DisplayName("등록된 상품들을 조회할 수 있다.") @Test void findAll() { //given - given(productRepository.findAll()).willReturn(Arrays.asList(뿌링클, 콜라)); + productRepository.save(뿌링클); + productRepository.save(콜라); //when List products = productService.findAll(); //then - assertThat(products).containsExactly(뿌링클, 콜라); + assertThat(products).hasSize(2); + + } + private Product 상품_생성(String name) { + return 상품_생성(name, BigDecimal.valueOf(1_000L)); } - private Product 상품_금액(long price) { - return 상품_금액(BigDecimal.valueOf(price)); + private Product 상품_생성(long price) { + return 상품_생성(BigDecimal.valueOf(price)); } - private Product 상품_금액(BigDecimal price) { + private Product 상품_생성(BigDecimal price) { + return 상품_생성("상품", price); + } + + private Product 상품_생성(String name, BigDecimal price) { Product product = new Product(); + product.setName(name); product.setPrice(price); return product; } From cb050cc8dcdd9d94d7529c4ae963c52e2d8ec35e Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 16 Mar 2022 23:10:00 +0900 Subject: [PATCH 14/40] =?UTF-8?q?test:=20=EC=8B=9D=ED=83=81=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mock 대신 fake 객체 활용 DisplayName을 요구사항과 일치하도록 변경 --- .../kitchenpos/domain/OrderRepository.java | 14 +- .../domain/OrderTableRepository.java | 14 +- .../application/InMemoryOrderRepository.java | 41 +++++ .../InMemoryOrderTableRepository.java | 32 ++++ .../application/OrderTableServiceTest.java | 156 ++++++++++-------- 5 files changed, 182 insertions(+), 75 deletions(-) create mode 100644 src/test/java/kitchenpos/application/InMemoryOrderRepository.java create mode 100644 src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java diff --git a/src/main/java/kitchenpos/domain/OrderRepository.java b/src/main/java/kitchenpos/domain/OrderRepository.java index d3c51d32c..94f92b8a0 100644 --- a/src/main/java/kitchenpos/domain/OrderRepository.java +++ b/src/main/java/kitchenpos/domain/OrderRepository.java @@ -1,9 +1,21 @@ package kitchenpos.domain; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; -public interface OrderRepository extends JpaRepository { +public interface OrderRepository { + + Optional findById(UUID orderId); boolean existsByOrderTableAndStatusNot(OrderTable orderTable, OrderStatus status); + + Order save(Order order); + + List findAll(); +} + +interface JpaOrderRepository extends OrderRepository, JpaRepository { + } diff --git a/src/main/java/kitchenpos/domain/OrderTableRepository.java b/src/main/java/kitchenpos/domain/OrderTableRepository.java index 0e732b0fc..cfa8e5d70 100644 --- a/src/main/java/kitchenpos/domain/OrderTableRepository.java +++ b/src/main/java/kitchenpos/domain/OrderTableRepository.java @@ -1,8 +1,20 @@ package kitchenpos.domain; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; -public interface OrderTableRepository extends JpaRepository { +public interface OrderTableRepository { + + Optional findById(UUID orderTableId); + + OrderTable save(OrderTable orderTable); + + List findAll(); +} + +interface JpaOrderTableRepository extends OrderTableRepository, JpaRepository { + } diff --git a/src/test/java/kitchenpos/application/InMemoryOrderRepository.java b/src/test/java/kitchenpos/application/InMemoryOrderRepository.java new file mode 100644 index 000000000..0692558e7 --- /dev/null +++ b/src/test/java/kitchenpos/application/InMemoryOrderRepository.java @@ -0,0 +1,41 @@ +package kitchenpos.application; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import kitchenpos.domain.Order; +import kitchenpos.domain.OrderRepository; +import kitchenpos.domain.OrderStatus; +import kitchenpos.domain.OrderTable; + +public class InMemoryOrderRepository implements OrderRepository { + + private final Map orders = new HashMap<>(); + + @Override + public Optional findById(UUID orderId) { + return Optional.ofNullable(orders.get(orderId)); + } + + @Override + public boolean existsByOrderTableAndStatusNot(OrderTable orderTable, OrderStatus status) { + return orders.values().stream() + .anyMatch( + order -> order.getOrderTableId().equals(orderTable.getId()) && !order.getStatus().equals(status)); + } + + @Override + public Order save(Order order) { + order.setId(UUID.randomUUID()); + orders.put(order.getId(), order); + return order; + } + + @Override + public List findAll() { + return new ArrayList<>(orders.values()); + } +} diff --git a/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java b/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java new file mode 100644 index 000000000..62baaa6dc --- /dev/null +++ b/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java @@ -0,0 +1,32 @@ +package kitchenpos.application; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import kitchenpos.domain.OrderTable; +import kitchenpos.domain.OrderTableRepository; + +public class InMemoryOrderTableRepository implements OrderTableRepository { + + private final Map orderTables = new HashMap<>(); + + @Override + public Optional findById(UUID orderTableId) { + return Optional.ofNullable(orderTables.get(orderTableId)); + } + + @Override + public OrderTable save(OrderTable orderTable) { + orderTable.setId(UUID.randomUUID()); + orderTables.put(orderTable.getId(), orderTable); + return orderTable; + } + + @Override + public List findAll() { + return new ArrayList<>(orderTables.values()); + } +} diff --git a/src/test/java/kitchenpos/application/OrderTableServiceTest.java b/src/test/java/kitchenpos/application/OrderTableServiceTest.java index d3dc609f4..98fcdb4e4 100644 --- a/src/test/java/kitchenpos/application/OrderTableServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderTableServiceTest.java @@ -6,41 +6,36 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import java.util.Arrays; import java.util.List; -import java.util.Optional; -import java.util.UUID; +import kitchenpos.domain.Order; import kitchenpos.domain.OrderRepository; import kitchenpos.domain.OrderStatus; import kitchenpos.domain.OrderTable; import kitchenpos.domain.OrderTableRepository; import org.assertj.core.api.Assertions; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; import org.junit.jupiter.params.provider.NullAndEmptySource; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -@DisplayName("식탁") -@ExtendWith(MockitoExtension.class) +@DisplayName("식탁 관리") class OrderTableServiceTest { - @Mock - private OrderTableRepository orderTableRepository; - @Mock - private OrderRepository orderRepository; - - @InjectMocks + private final OrderTableRepository orderTableRepository = new InMemoryOrderTableRepository(); + private final OrderRepository orderRepository = new InMemoryOrderRepository(); private OrderTableService orderTableService; - @DisplayName("식탁 생성 예외 - 식탁 이름 없음") + @BeforeEach + void setUp() { + orderTableService = new OrderTableService(orderTableRepository, orderRepository); + } + + @DisplayName("식탁은 이름이 있어야 한다.") @ParameterizedTest(name = "식탁 이름: [{arguments}]") @NullAndEmptySource void createException(String orderTableName) { @@ -54,117 +49,124 @@ void createException(String orderTableName) { assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("식탁 생성") + @DisplayName("식탁을 생성한다. 식탁의 기본 상태는 0명의 손님이며 비어있다.") @Test void create() { //given OrderTable 신규_테이블 = 식탁_생성("3번"); - given(orderTableRepository.save(any(OrderTable.class))).willReturn(삼번_테이블); //when OrderTable orderTable = orderTableService.create(신규_테이블); //then assertAll( - () -> assertThat(orderTable.getName()).isEqualTo("3번"), + () -> assertThat(orderTable.getName()).isEqualTo(신규_테이블.getName()), () -> assertThat(orderTable.getNumberOfGuests()).isZero(), () -> assertThat(orderTable.isEmpty()).isTrue() ); } - @DisplayName("손님 착석") + @DisplayName("손님이 앉을 수 있다. 손님이 앉으면 착석 상태다.") @Test void sit() { //given - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + OrderTable 빈_식탁 = 빈_식탁(); + orderTableRepository.save(빈_식탁); //when - OrderTable orderTable = orderTableService.sit(일번_테이블.getId()); - - boolean actual = orderTable.isEmpty(); + OrderTable actual = orderTableService.sit(빈_식탁.getId()); //then - assertThat(actual).isFalse(); + assertThat(actual.isEmpty()).isFalse(); } - @DisplayName("식탁 정리 예외 - 주문완료되지 않은 식탁") + + @DisplayName("착석한 손님의 수를 0명 미만으로 변경할 수 없다.") @Test - void clearException() { + void changeNumberOfGuestsException() { //given - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); - given(orderRepository.existsByOrderTableAndStatusNot(any(OrderTable.class), any(OrderStatus.class))) - .willReturn(true); + OrderTable 손님_수_변경 = 식탁_생성(-1); //when - ThrowingCallable actual = () -> orderTableService.clear(일번_테이블.getId()); + ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); //then - assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("식탁 정리") + @DisplayName("착석하지 않은 식탁은 손님 수를 변경할 수 없다.") @Test - void clear() { + void tableIsEmptyThenChangeNumberOfGuestsException() { //given - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); - given(orderRepository.existsByOrderTableAndStatusNot(any(OrderTable.class), any(OrderStatus.class))) - .willReturn(false); + OrderTable 빈_식탁 = 빈_식탁(); + orderTableRepository.save(빈_식탁); + + OrderTable 손님_수_변경 = 식탁_생성(3); //when - OrderTable cleanTable = orderTableService.clear(일번_테이블.getId()); + ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(빈_식탁.getId(), 손님_수_변경); //then - assertAll( - () -> Assertions.assertThat(cleanTable.getNumberOfGuests()).isZero(), - () -> Assertions.assertThat(cleanTable.isEmpty()).isTrue() - ); - + assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); } - @DisplayName("손님 수 변경 예외 - 0명 미만으로 변경 불가") + @DisplayName("착석한 손님의 수를 변경할 수 있다.") @Test - void changeNumberOfGuestsException() { + void changeNumberOfGuests() { //given - OrderTable 손님_수_변경 = 식탁_생성("1번 테이블 손님", -1); + OrderTable 삼번_테이블 = 식탁_생성("3번 테이블", 3, false); + orderTableRepository.save(삼번_테이블); + OrderTable 손님_수_변경 = 식탁_생성(4); //when - ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + OrderTable orderTable = orderTableService.changeNumberOfGuests(삼번_테이블.getId(), 손님_수_변경); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertAll( + () -> assertThat(orderTable.getNumberOfGuests()).isEqualTo(4), + () -> assertThat(orderTable.isEmpty()).isFalse() + ); } - @DisplayName("손님 수 변경 예외 - 착석하지 않은 식탁") - @Test - void tableIsEmptyThenChangeNumberOfGuestsException() { + @DisplayName("주문완료되지 않은 식탁은 정리할 수 없다.") + @ParameterizedTest + @EnumSource(value = OrderStatus.class, names = {"COMPLETED"}, mode = Mode.EXCLUDE) + void clearException(OrderStatus orderStatus) { //given - OrderTable 손님_수_변경 = 식탁_생성("1번 테이블 손님", 3); + OrderTable 삼번_테이블 = 식탁_생성("3번 테이블", 3, false); + orderTableRepository.save(삼번_테이블); - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + Order 매장_주문 = new Order(); + 매장_주문.setOrderTableId(삼번_테이블.getId()); + 매장_주문.setStatus(orderStatus); + orderRepository.save(매장_주문); //when - ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + ThrowingCallable actual = () -> orderTableService.clear(삼번_테이블.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); } - @DisplayName("손님 수 변경") + @DisplayName("주문 완료된 식탁은 정리할 수 있다. 정리된 식탁은 기본 상태가 된다.") @Test - void changeNumberOfGuests() { + void clear() { //given - OrderTable 손님_수_변경 = 식탁_생성("3번 테이블 손님", 3); + OrderTable 삼번_테이블 = 식탁_생성("3번 테이블", 3, false); + orderTableRepository.save(삼번_테이블); - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); - orderTableService.sit(일번_테이블.getId()); + Order 매장_주문 = new Order(); + 매장_주문.setOrderTableId(삼번_테이블.getId()); + 매장_주문.setStatus(OrderStatus.COMPLETED); + orderRepository.save(매장_주문); //when - OrderTable orderTable = orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + OrderTable cleanTable = orderTableService.clear(삼번_테이블.getId()); //then assertAll( - () -> assertThat(orderTable.getNumberOfGuests()).isEqualTo(3), - () -> assertThat(orderTable.isEmpty()).isFalse() + () -> Assertions.assertThat(cleanTable.getNumberOfGuests()).isZero(), + () -> Assertions.assertThat(cleanTable.isEmpty()).isTrue() ); } @@ -172,7 +174,8 @@ void changeNumberOfGuests() { @Test void findAll() { //given - given(orderTableRepository.findAll()).willReturn(Arrays.asList(일번_테이블, 삼번_테이블)); + orderTableRepository.save(일번_테이블); + orderTableRepository.save(삼번_테이블); //when List orderTables = orderTableService.findAll(); @@ -180,20 +183,27 @@ void findAll() { //then assertAll( () -> assertThat(orderTables).hasSize(2), - () -> assertThat(orderTables).containsExactly(일번_테이블, 삼번_테이블) + () -> assertThat(orderTables).contains(일번_테이블, 삼번_테이블) ); } - private OrderTable 식탁_생성(String orderTableName) { - OrderTable orderTable = new OrderTable(); - orderTable.setName(orderTableName); - return orderTable; + private OrderTable 식탁_생성(String name) { + return 식탁_생성(name, 0, true); } - private OrderTable 식탁_생성(String orderTableName, int numberOfGuests) { - OrderTable orderTable = 식탁_생성(orderTableName); + private OrderTable 빈_식탁() { + return 식탁_생성("빈 식탁", 0, true); + } + + private OrderTable 식탁_생성(int numberOfGuests) { + return 식탁_생성("이름없는 식탁", numberOfGuests, false); + } + + private OrderTable 식탁_생성(String name, int numberOfGuests, boolean empty) { + OrderTable orderTable = new OrderTable(); + orderTable.setName(name); orderTable.setNumberOfGuests(numberOfGuests); - orderTable.setEmpty(false); + orderTable.setEmpty(empty); return orderTable; } } From ad7f1f35a5acec40925b9508ef0ee6042a70a1e8 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 19 Mar 2022 12:17:57 +0900 Subject: [PATCH 15/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mock 대신 fake 객체 활용 --- .../kitchenpos/application/MenuService.java | 29 +- .../application/MenuServiceTest.java | 260 ++++++++++-------- 2 files changed, 157 insertions(+), 132 deletions(-) diff --git a/src/main/java/kitchenpos/application/MenuService.java b/src/main/java/kitchenpos/application/MenuService.java index b68950be5..0fb63ff8f 100644 --- a/src/main/java/kitchenpos/application/MenuService.java +++ b/src/main/java/kitchenpos/application/MenuService.java @@ -1,31 +1,40 @@ package kitchenpos.application; -import kitchenpos.domain.*; -import kitchenpos.infra.PurgomalumClient; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; +import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuGroup; +import kitchenpos.domain.MenuGroupRepository; +import kitchenpos.domain.MenuProduct; +import kitchenpos.domain.MenuRepository; +import kitchenpos.domain.Product; +import kitchenpos.domain.ProductRepository; +import kitchenpos.infra.ProfanityClient; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service public class MenuService { private final MenuRepository menuRepository; private final MenuGroupRepository menuGroupRepository; private final ProductRepository productRepository; - private final PurgomalumClient purgomalumClient; + private final ProfanityClient profanityClient; public MenuService( final MenuRepository menuRepository, final MenuGroupRepository menuGroupRepository, final ProductRepository productRepository, - final PurgomalumClient purgomalumClient + final ProfanityClient profanityClient ) { this.menuRepository = menuRepository; this.menuGroupRepository = menuGroupRepository; this.productRepository = productRepository; - this.purgomalumClient = purgomalumClient; + this.profanityClient = profanityClient; } @Transactional @@ -70,7 +79,7 @@ public Menu create(final Menu request) { throw new IllegalArgumentException(); } final String name = request.getName(); - if (Objects.isNull(name) || purgomalumClient.containsProfanity(name)) { + if (Objects.isNull(name) || profanityClient.containsProfanity(name)) { throw new IllegalArgumentException(); } final Menu menu = new Menu(); diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index af358df01..fe2b06283 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -1,179 +1,166 @@ package kitchenpos.application; -import static kitchenpos.application.MenuFixture.뿌링클_세트; import static kitchenpos.application.MenuGroupFixture.세트메뉴; import static kitchenpos.application.MenuProductFixture.맛초킹_1개; import static kitchenpos.application.MenuProductFixture.콜라_1개; import static kitchenpos.application.MenuProductFixture.콜라_수량_오류; import static kitchenpos.application.ProductFixture.맛초킹; -import static kitchenpos.application.ProductFixture.뿌링클; import static kitchenpos.application.ProductFixture.콜라; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Stream; import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuGroup; import kitchenpos.domain.MenuGroupRepository; +import kitchenpos.domain.MenuProduct; import kitchenpos.domain.MenuRepository; +import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; -import kitchenpos.infra.PurgomalumClient; +import kitchenpos.infra.ProfanityClient; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@DisplayName("메뉴") -@ExtendWith(MockitoExtension.class) +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +@DisplayName("메뉴 관리") class MenuServiceTest { - @Mock - private MenuRepository menuRepository; - @Mock - private MenuGroupRepository menuGroupRepository; - @Mock - private ProductRepository productRepository; - @Mock(lenient = true) - private PurgomalumClient purgomalumClient; + private final MenuRepository menuRepository = new InMemoryMenuRepository(); + private final MenuGroupRepository menuGroupRepository = new InMemoryMenuGroupRepository(); + private final ProductRepository productRepository = new InMemoryProductRepository(); + private final ProfanityClient profanityClient = new FakeProfanityClient(); - @InjectMocks private MenuService menuService; - private Menu 맛초킹_세트; - @BeforeEach void setUp() { - 맛초킹_세트 = new Menu(); - 맛초킹_세트.setName("맛초킹 세트"); - 맛초킹_세트.setMenuGroup(세트메뉴); - 맛초킹_세트.setMenuGroupId(세트메뉴.getId()); - 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)); - 맛초킹_세트.setPrice(BigDecimal.valueOf(11_000L)); - 맛초킹_세트.setDisplayed(true); + menuService = new MenuService(menuRepository, menuGroupRepository, productRepository, profanityClient); } - @DisplayName("메뉴 생성 예외 - 메뉴 가격 0원 미만") - @Test - void createPriceUnderZeroException() { + @DisplayName("메뉴의 가격은 0원 이상이어야 한다.") + @ParameterizedTest + @ValueSource(strings = {"-1"}) + @NullSource + void createPriceUnderZeroException(BigDecimal price) { //given - 맛초킹_세트.setPrice(BigDecimal.valueOf(-1L)); + Menu 잘못된_가격의_메뉴 = 메뉴_생성(price); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(잘못된_가격의_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("메뉴 생성 예외 - 메뉴 그룹 없음") + @DisplayName("메뉴는 메뉴 그룹에 속해야 한다.") @Test void createMenuGroupNotExistException() { //given - 맛초킹_세트.setMenuGroup(null); + Menu 메뉴_그룹_없는_메뉴 = 메뉴_생성(11_000); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(메뉴_그룹_없는_메뉴); //then assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); } - @DisplayName("메뉴 생성 예외 - 메뉴 상품 없음") + @DisplayName("메뉴는 1개 이상의 상품을 포함해야 한다.") @Test void createMenuProductsNotExistException() { //given - 맛초킹_세트.setMenuProducts(null); + MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); + Menu 상품_없는_메뉴 = 메뉴_생성(11_000); + 상품_없는_메뉴.setMenuGroupId(세트_메뉴.getId()); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(상품_없는_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("메뉴 생성 예외 - 메뉴 상품 개수 미일치") + @DisplayName("중복된 메뉴상품을 가질 수 없다.") @Test void createMenuProductsMismatchException() { //given - 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹_1개, 맛초킹_1개, 콜라_1개)); + MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); + productRepository.save(맛초킹); + productRepository.save(콜라); - given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); - given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); + Menu 상품_없는_메뉴 = 메뉴_생성(11_000); + 상품_없는_메뉴.setMenuGroupId(세트_메뉴.getId()); + 상품_없는_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 맛초킹_1개, 콜라_1개)); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(상품_없는_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("메뉴 생성 예외 - 메뉴 상품 수량 부족") + @DisplayName("메뉴는 수량이 부족한 상품을 포함할 수 없다.") @Test void createMenuProductsLackQuantityException() { - 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_수량_오류)); + //given + MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); + productRepository.save(맛초킹); + productRepository.save(콜라); - given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); - given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); - given(productRepository.findById(맛초킹.getId())).willReturn(Optional.of(맛초킹)); + Menu 상품_수량_오류_메뉴 = 메뉴_생성(11_000); + 상품_수량_오류_메뉴.setMenuGroupId(세트_메뉴.getId()); + 상품_수량_오류_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_수량_오류)); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(상품_수량_오류_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("메뉴 생성 예외 - 상품들의 총 가격보다 높음") + @DisplayName("메뉴의 가격은 상품들의 합산 가격과 같거나 작아야 한다.") @Test void createPriceException() { //given - 맛초킹_세트.setPrice(BigDecimal.valueOf(15_000L)); + MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); + productRepository.save(맛초킹); + productRepository.save(콜라); - given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); - given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); - given(productRepository.findById(맛초킹.getId())).willReturn(Optional.of(맛초킹)); - given(productRepository.findById(콜라.getId())).willReturn(Optional.of(콜라)); + Menu 비싼_메뉴 = 메뉴_생성(15_000); + 비싼_메뉴.setMenuGroupId(세트_메뉴.getId()); + 비싼_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(비싼_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("메뉴 생성 예외 - 이름에 비속어 포함") + @DisplayName("메뉴 이름에는 비속어가 포함될 수 없다.") @Test void createNameException() { //given - 맛초킹_세트.setName("비속어"); + MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); + productRepository.save(맛초킹); + productRepository.save(콜라); - given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); - given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(맛초킹, 콜라)); - given(productRepository.findById(맛초킹.getId())).willReturn(Optional.of(맛초킹)); - given(productRepository.findById(콜라.getId())).willReturn(Optional.of(콜라)); - given(purgomalumClient.containsProfanity("비속어")).willReturn(true); + Menu 비속어_메뉴 = 메뉴_생성(11_000); + 비속어_메뉴.setMenuGroupId(세트_메뉴.getId()); + 비속어_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)); + 비속어_메뉴.setName("비속어"); //when - ThrowingCallable actual = () -> menuService.create(맛초킹_세트); + ThrowingCallable actual = () -> menuService.create(비속어_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); @@ -183,59 +170,46 @@ void createNameException() { @Test void create() { //given - given(menuGroupRepository.findById(any(UUID.class))).willReturn(Optional.of(세트메뉴)); - given(productRepository.findAllByIdIn(anyList())).willReturn(Arrays.asList(뿌링클, 콜라)); - given(productRepository.findById(뿌링클.getId())).willReturn(Optional.of(뿌링클)); - given(productRepository.findById(콜라.getId())).willReturn(Optional.of(콜라)); - given(purgomalumClient.containsProfanity(anyString())).willReturn(false); - given(menuRepository.save(any(Menu.class))).willReturn(뿌링클_세트); + Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); //when - Menu menu = menuService.create(뿌링클_세트); + Menu menu = menuService.create(맛초킹_세트); //then assertAll( - () -> assertThat(menu.getName()).isEqualTo("뿌링클 세트"), - () -> assertThat(menu.getMenuGroupId()).isEqualTo(세트메뉴.getId()), + () -> assertThat(menu.getName()).isEqualTo(맛초킹_세트.getName()), () -> assertThat(menu.getMenuProducts()).hasSize(2), - () -> assertThat(menu.getPrice()).isEqualTo(뿌링클_세트.getPrice()), - () -> assertThat(menu.isDisplayed()).isTrue() + () -> assertThat(menu.getPrice()).isEqualTo(맛초킹_세트.getPrice()), + () -> assertThat(menu.isDisplayed()).isEqualTo(맛초킹_세트.isDisplayed()) ); } - @DisplayName("가격 변경 예외 - 0원 미만") + @DisplayName("가격을 0원 미만으로 변경할 수 없다.") @ParameterizedTest(name = "변경 가격: [{arguments}]") - @MethodSource("changePriceException") + @ValueSource(strings = {"-1"}) + @NullSource void changePriceException(BigDecimal price) { //given - 맛초킹_세트.setId(UUID.randomUUID()); - 맛초킹_세트.setPrice(price); + Menu 포장_전용_메뉴 = menuRepository.save(메뉴_생성(20_000)); + + Menu 가격_변경 = 메뉴_생성(price); //when - ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 맛초킹_세트); + ThrowingCallable actual = () -> menuService.changePrice(포장_전용_메뉴.getId(), 가격_변경); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - private static Stream changePriceException() { - return Stream.of( - Arguments.of((BigDecimal) null), - Arguments.of(BigDecimal.valueOf(-1)) - ); - } - - @DisplayName("가격 변경 예외 - 상품들의 총 가격보다 높음") + @DisplayName("상품들의 총 가격보다 높은 가격으로 변경할 수 없다.") @Test void changePriceGreaterThanProductsPricesException() { //given - 맛초킹_세트.setId(UUID.randomUUID()); - 맛초킹_세트.setPrice(BigDecimal.valueOf(15_000L)); - - given(menuRepository.findById(any(UUID.class))).willReturn(Optional.of(맛초킹_세트)); + Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); + Menu 가격_변경 = 메뉴_생성(50_000); //when - ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 맛초킹_세트); + ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 가격_변경); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); @@ -245,29 +219,38 @@ void changePriceGreaterThanProductsPricesException() { @Test void changePrice() { //given - Menu 변경할_가격 = new Menu(); - 변경할_가격.setPrice(BigDecimal.valueOf(10_500L)); - - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); + Menu 가격_인하 = 메뉴_생성(10_500); //when - Menu menu = menuService.changePrice(뿌링클_세트.getId(), 변경할_가격); + Menu menu = menuService.changePrice(맛초킹_세트.getId(), 가격_인하); BigDecimal actual = menu.getPrice(); //then assertThat(actual).isEqualTo(BigDecimal.valueOf(10_500L)); } - @DisplayName("진열 예외 - 상품들의 총 가격보다 높음") + @DisplayName("등록되지 않은 메뉴는 진열할 수 없다.") @Test - void displayException() { + void displayNotExistException() { //given - 맛초킹_세트.setPrice(BigDecimal.valueOf(15_000L)); + Menu 없는_메뉴 = new Menu(); + + //when + ThrowingCallable actual = () -> menuService.display(없는_메뉴.getId()); + + //then + assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); + } - given(menuRepository.findById(any())).willReturn(Optional.of(맛초킹_세트)); + @DisplayName("상품들의 총 가격보다 높은 메뉴는 진열할 수 없다.") + @Test + void displayException() { + //given + Menu 마진_대박_맛초킹_세트 = 맛초킹_세트_생성(50_000); //when - ThrowingCallable actual = () -> menuService.display(맛초킹_세트.getId()); + ThrowingCallable actual = () -> menuService.display(마진_대박_맛초킹_세트.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -277,9 +260,7 @@ void displayException() { @Test void display() { //given - 맛초킹_세트.setPrice(BigDecimal.valueOf(11_000L)); - - given(menuRepository.findById(any())).willReturn(Optional.of(맛초킹_세트)); + Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); //when Menu menu = menuService.display(맛초킹_세트.getId()); @@ -288,14 +269,14 @@ void display() { assertThat(menu.isDisplayed()).isTrue(); } - @DisplayName("진열 제외 - 등록된 메뉴만 진열 제외 가능") + @DisplayName("등록되지 않은 메뉴는 진열에서 제외할 수 없다.") @Test void hideException() { //given - given(menuRepository.findById(any())).willThrow(NoSuchElementException.class); + Menu 없는_메뉴 = new Menu(); //when - ThrowingCallable actual = () -> menuService.hide(뿌링클_세트.getId()); + ThrowingCallable actual = () -> menuService.hide(없는_메뉴.getId()); //then assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); @@ -305,7 +286,7 @@ void hideException() { @Test void hide() { //given - given(menuRepository.findById(any())).willReturn(Optional.of(맛초킹_세트)); + Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); //when Menu menu = menuService.hide(맛초킹_세트.getId()); @@ -318,7 +299,8 @@ void hide() { @Test void findALl() { //given - given(menuRepository.findAll()).willReturn(Arrays.asList(뿌링클_세트, 맛초킹_세트)); + menuRepository.save(메뉴_생성(10_000)); + menuRepository.save(메뉴_생성(20_000)); //when List actual = menuService.findAll(); @@ -327,4 +309,38 @@ void findALl() { assertThat(actual).hasSize(2); } + private Menu 맛초킹_세트_생성(int price) { + MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); + Product 맛초킹 = productRepository.save(ProductFixture.맛초킹); + Product 콜라 = productRepository.save(ProductFixture.콜라); + + MenuProduct 맛초킹1개 = 메뉴_상품_생성(맛초킹); + MenuProduct 콜라1개 = 메뉴_상품_생성(콜라); + + Menu 맛초킹_세트 = 메뉴_생성(price); + 맛초킹_세트.setMenuGroupId(세트_메뉴.getId()); + 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹1개, 콜라1개)); + 맛초킹_세트.setName("맛초킹 세트"); + + return menuRepository.save(맛초킹_세트); + } + + private MenuProduct 메뉴_상품_생성(Product product) { + MenuProduct menuProduct = new MenuProduct(); + menuProduct.setQuantity(1L); + menuProduct.setProduct(product); + menuProduct.setProductId(product.getId()); + return menuProduct; + } + + private Menu 메뉴_생성(int price) { + return 메뉴_생성(BigDecimal.valueOf(price)); + } + + private Menu 메뉴_생성(BigDecimal price) { + Menu menu = new Menu(); + menu.setPrice(price); + return menu; + } + } From b651be40cf1c9eb23e84573a60c4b78b011f1169 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 19 Mar 2022 18:51:55 +0900 Subject: [PATCH 16/40] =?UTF-8?q?test:=20=EC=A3=BC=EB=AC=B8=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mock 대신 fake 객체 활용 --- .../kitchenpos/application/OrderService.java | 58 ++- .../application/OrderServiceTest.java | 430 ++++++++++-------- 2 files changed, 286 insertions(+), 202 deletions(-) diff --git a/src/main/java/kitchenpos/application/OrderService.java b/src/main/java/kitchenpos/application/OrderService.java index b2db0580d..626fc6cdf 100644 --- a/src/main/java/kitchenpos/application/OrderService.java +++ b/src/main/java/kitchenpos/application/OrderService.java @@ -33,11 +33,11 @@ public OrderService( public Order create(final Order request) { final OrderType type = request.getType(); if (Objects.isNull(type)) { - throw new IllegalArgumentException(); + throw new OrderTypeNotExistException(); } final List orderLineItemRequests = request.getOrderLineItems(); if (Objects.isNull(orderLineItemRequests) || orderLineItemRequests.isEmpty()) { - throw new IllegalArgumentException(); + throw new OrderLineItemNotExistException(); } final List menus = menuRepository.findAllByIdIn( orderLineItemRequests.stream() @@ -45,23 +45,24 @@ public Order create(final Order request) { .collect(Collectors.toList()) ); if (menus.size() != orderLineItemRequests.size()) { - throw new IllegalArgumentException(); + throw new OrderLineItemNotMatchException(); } final List orderLineItems = new ArrayList<>(); for (final OrderLineItem orderLineItemRequest : orderLineItemRequests) { final long quantity = orderLineItemRequest.getQuantity(); if (type != OrderType.EAT_IN) { if (quantity < 0) { - throw new IllegalArgumentException(); + throw new OrderInvalidQuantityException(quantity); } } final Menu menu = menuRepository.findById(orderLineItemRequest.getMenuId()) .orElseThrow(NoSuchElementException::new); if (!menu.isDisplayed()) { - throw new IllegalStateException(); + throw new OrderDisplayException(); } if (menu.getPrice().compareTo(orderLineItemRequest.getPrice()) != 0) { - throw new IllegalArgumentException(); + throw new OrderLineItemPriceException(menu.getName(), menu.getPrice().longValue(), + orderLineItemRequest.getPrice().longValue()); } final OrderLineItem orderLineItem = new OrderLineItem(); orderLineItem.setMenu(menu); @@ -77,7 +78,7 @@ public Order create(final Order request) { if (type == OrderType.DELIVERY) { final String deliveryAddress = request.getDeliveryAddress(); if (Objects.isNull(deliveryAddress) || deliveryAddress.isEmpty()) { - throw new IllegalArgumentException(); + throw new OrderDeliveryAddressException(); } order.setDeliveryAddress(deliveryAddress); } @@ -179,4 +180,47 @@ public Order complete(final UUID orderId) { public List findAll() { return orderRepository.findAll(); } + + + static class OrderTypeNotExistException extends IllegalStateException { + public OrderTypeNotExistException() { + super("주문 유형이 올바르지 않습니다"); + } + } + + static class OrderLineItemNotExistException extends IllegalStateException { + public OrderLineItemNotExistException() { + super("주문 상품이 없습니다."); + } + } + + static class OrderLineItemNotMatchException extends IllegalStateException { + public OrderLineItemNotMatchException() { + super("등록되지 않은 메뉴는 주문할 수 없습니다."); + } + } + + static class OrderInvalidQuantityException extends IllegalStateException { + public OrderInvalidQuantityException(long quantity) { + super("최소 주문 수량은 0개 이상입니다. 주문 수량 : " + quantity); + } + } + + static class OrderDisplayException extends IllegalStateException { + public OrderDisplayException() { + super("진열되지 않은 메뉴는 주문할 수 없습니다."); + } + } + + static class OrderLineItemPriceException extends IllegalArgumentException { + public OrderLineItemPriceException(String menu, long menuPrice, long requestPrice) { + super("가격이 일치하지 않습니다. 메뉴명: " + menu + ", 메뉴 가격: " + menuPrice + ", 지불 가격: " + requestPrice); + } + } + + static class OrderDeliveryAddressException extends IllegalArgumentException { + public OrderDeliveryAddressException() { + super("배달 주소가 없습니다."); + } + } } diff --git a/src/test/java/kitchenpos/application/OrderServiceTest.java b/src/test/java/kitchenpos/application/OrderServiceTest.java index d0b23d43e..8906b0976 100644 --- a/src/test/java/kitchenpos/application/OrderServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderServiceTest.java @@ -1,35 +1,28 @@ package kitchenpos.application; import static kitchenpos.application.MenuFixture.뿌링클_세트; -import static kitchenpos.application.OrderFixture.매장_주문; -import static kitchenpos.application.OrderFixture.배달_주문; -import static kitchenpos.application.OrderFixture.포장_주문; -import static kitchenpos.application.OrderTableFixture.일번_테이블; -import static kitchenpos.application.OrderTableFixture.착석_테이블; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Optional; -import java.util.UUID; import java.util.stream.Stream; +import kitchenpos.application.OrderService.OrderDeliveryAddressException; +import kitchenpos.application.OrderService.OrderDisplayException; +import kitchenpos.application.OrderService.OrderInvalidQuantityException; +import kitchenpos.application.OrderService.OrderLineItemNotExistException; +import kitchenpos.application.OrderService.OrderLineItemNotMatchException; +import kitchenpos.application.OrderService.OrderLineItemPriceException; +import kitchenpos.application.OrderService.OrderTypeNotExistException; import kitchenpos.domain.Menu; import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Order; import kitchenpos.domain.OrderLineItem; import kitchenpos.domain.OrderRepository; import kitchenpos.domain.OrderStatus; +import kitchenpos.domain.OrderTable; import kitchenpos.domain.OrderTableRepository; import kitchenpos.domain.OrderType; import kitchenpos.infra.KitchenridersClient; @@ -37,204 +30,173 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.NullAndEmptySource; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -@DisplayName("주문") -@ExtendWith(MockitoExtension.class) +@DisplayName("주문 관리") class OrderServiceTest { - @Mock - private OrderRepository orderRepository; - @Mock - private MenuRepository menuRepository; - @Mock - private OrderTableRepository orderTableRepository; - @Mock - private KitchenridersClient kitchenridersClient; + private final OrderRepository orderRepository = new InMemoryOrderRepository(); + private final MenuRepository menuRepository = new InMemoryMenuRepository(); + private final OrderTableRepository orderTableRepository = new InMemoryOrderTableRepository(); + private final KitchenridersClient kitchenridersClient = new KitchenridersClient(); - @InjectMocks private OrderService orderService; - private Order 신규_주문; - @BeforeEach void setUp() { - 신규_주문 = new Order(); - 신규_주문.setId(UUID.randomUUID()); - 신규_주문.setType(OrderType.DELIVERY); - OrderLineItem orderLineItem = new OrderLineItem(); - orderLineItem.setMenu(뿌링클_세트); - orderLineItem.setMenuId(뿌링클_세트.getId()); - orderLineItem.setQuantity(1L); - orderLineItem.setPrice(뿌링클_세트.getPrice()); - 신규_주문.setOrderLineItems(Collections.singletonList(orderLineItem)); - 신규_주문.setDeliveryAddress("배달주소"); - 신규_주문.setOrderTableId(일번_테이블.getId()); - 신규_주문.setOrderTable(일번_테이블); - 신규_주문.setStatus(OrderStatus.WAITING); - 신규_주문.setOrderDateTime(LocalDateTime.now()); - } - - @DisplayName("주문 예외 - 주문 유형 없음") + orderService = new OrderService(orderRepository, menuRepository, orderTableRepository, kitchenridersClient); + } + + @DisplayName("주문 유형이 반드시 있어야 한다.") @Test void createOrderTypeException() { //given - 신규_주문.setType(null); + Order order = new Order(); //when - ThrowingCallable actual = () -> orderService.create(new Order()); + ThrowingCallable actual = () -> orderService.create(order); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(OrderTypeNotExistException.class); } - - - @DisplayName("주문 예외 - 주문 메뉴 없음") + @DisplayName("상품없이 주문할 수 없다.") @ParameterizedTest(name = "주문 메뉴: [{arguments}]") @NullAndEmptySource void createOrderHasNoMenuException(List orderLineItems) { //given - 신규_주문.setOrderLineItems(orderLineItems); + Order 상품_없는_주문 = 신규_배달_주문(orderLineItems); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(상품_없는_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(OrderLineItemNotExistException.class); } - @DisplayName("주문 예외 - 등록되지 않은 메뉴 주문") + @DisplayName("등록되지 않은 상품은 주문할 수 없다.") @Test void createOrderInvalidMenuException() { //given - given(menuRepository.findAllByIdIn(anyList())).willReturn(new ArrayList<>()); + OrderLineItem 등록_되지_않은_상품 = 주문_항목_1개(new Menu()); + Order 등록되지_않은_상품_주문 = 신규_배달_주문(Collections.singletonList(등록_되지_않은_상품)); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(등록되지_않은_상품_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(OrderLineItemNotMatchException.class); } - @DisplayName("주문 예외 - 포장 또는 배달 메뉴 수량 미달") + @DisplayName("포장 또는 배달 주문인 경우 0개 미만의 수량으로 주문할 수 없다.") @ParameterizedTest(name = "메뉴 유형: [{arguments}]") @EnumSource(value = OrderType.class, names = {"DELIVERY", "TAKEOUT"}) void createOrderInvalidQuantityException(OrderType orderType) { //given - 신규_주문.setType(orderType); - OrderLineItem 모자란_수량 = new OrderLineItem(); - 모자란_수량.setQuantity(-1L); - 신규_주문.setOrderLineItems(Collections.singletonList(모자란_수량)); - - given(menuRepository.findAllByIdIn(anyList())).willReturn(new ArrayList<>()); + Menu menu = menuRepository.save(뿌링클_세트); + OrderLineItem 모자란_수량 = 주문_항목(menu, -1); + Order 신규_배달_주문 = 신규_주문(orderType, Collections.singletonList(모자란_수량)); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(신규_배달_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(OrderInvalidQuantityException.class); } - @DisplayName("주문 예외 - 진열되지 않은 메뉴 주문") + @DisplayName("진열되지 않은 상품은 주문할 수 없다.") @Test void createOrderNotDisplayedMenuException() { //given - Menu 진열되지_않은_메뉴 = new Menu(); - 진열되지_않은_메뉴.setDisplayed(false); - - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(진열되지_않은_메뉴)); + Menu 진열되지_않은_메뉴 = menuRepository.save(new Menu()); + List 진열되지_않은_메뉴_상품 = Collections.singletonList(주문_항목_1개(진열되지_않은_메뉴)); + Order 진열되지_않은_상품_주문 = 신규_배달_주문(진열되지_않은_메뉴_상품); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(진열되지_않은_상품_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + assertThatThrownBy(actual).isInstanceOf(OrderDisplayException.class); } - @DisplayName("주문 예외 - 가격 불일치") + @DisplayName("상품가격과 일치하지 않은 금액으로 주문할 수 없다.") @Test void createOrderMismatchPriceException() { //given - OrderLineItem 모자란_금액 = new OrderLineItem(); - 모자란_금액.setPrice(BigDecimal.valueOf(10_000L)); - - 신규_주문.setOrderLineItems(Collections.singletonList(모자란_금액)); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + List 모자란_금액 = Collections.singletonList(주문_항목_1개(뿌링클_세트, 8_000)); + Order 모자란_금액_주문 = 신규_배달_주문(모자란_금액); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(모자란_금액_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(OrderLineItemPriceException.class); } - @DisplayName("주문 예외 - 배달 주문 시 배달 주소 없음") + @DisplayName("배달 주문인 경우 배달 주소가 반드시 있어야 한다.") @ParameterizedTest(name = "배달 주소: [{arguments}]") @NullAndEmptySource void createDeliveryOrderHasNoAddressException(String deliveryAddress) { //given - 신규_주문.setDeliveryAddress(deliveryAddress); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + Order 주소_없는_배달_주문 = 신규_배달_주문(뿌링클_1개, deliveryAddress); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(주소_없는_배달_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(OrderDeliveryAddressException.class); } - @DisplayName("주문 예외 - 식당 내 주문 시 착석하지 않음") + @DisplayName("식탁에 착석하지 않으면 매장 주문을 할 수 없다.") @Test void createEatInException() { //given - 신규_주문.setType(OrderType.EAT_IN); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(일번_테이블)); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + Order 착석하지_않고_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); + OrderTable orderTable1 = new OrderTable(); + orderTable1.setEmpty(true); + OrderTable orderTable = orderTableRepository.save(orderTable1); + 착석하지_않고_주문.setOrderTable(orderTable); + 착석하지_않고_주문.setOrderTableId(orderTable.getId()); //when - ThrowingCallable actual = () -> orderService.create(신규_주문); + ThrowingCallable actual = () -> orderService.create(착석하지_않고_주문); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); } - @DisplayName("매장 주문 성공") + @DisplayName("매장 식당 주문") @Test void createOrderEatIn() { //given - 신규_주문.setType(OrderType.EAT_IN); - 신규_주문.setOrderTableId(착석_테이블.getId()); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + OrderTable orderTable = orderTableRepository.save(착석한_식탁()); - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); - given(orderTableRepository.findById(any(UUID.class))).willReturn(Optional.of(착석_테이블)); - given(orderRepository.save(any(Order.class))).willReturn(신규_주문); + Order 매장_식사_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); + 매장_식사_주문.setOrderTableId(orderTable.getId()); //when - Order order = orderService.create(신규_주문); + Order order = orderService.create(매장_식사_주문); //then assertAll( () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), () -> assertThat(order.getType()).isEqualTo(OrderType.EAT_IN), - () -> assertThat(order.getOrderDateTime()).isEqualTo(신규_주문.getOrderDateTime()), - () -> assertThat(order.getOrderTableId()).isEqualTo(착석_테이블.getId()) + () -> assertThat(order.getOrderTable().getId()).isEqualTo(orderTable.getId()) ); } @@ -242,20 +204,18 @@ void createOrderEatIn() { @Test void createOrderTakeout() { //given - 신규_주문.setType(OrderType.TAKEOUT); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); - given(orderRepository.save(any(Order.class))).willReturn(신규_주문); + Order 포장_식사_주문 = 신규_주문(OrderType.TAKEOUT, 뿌링클_1개); //when - Order order = orderService.create(신규_주문); + Order order = orderService.create(포장_식사_주문); //then assertAll( () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), - () -> assertThat(order.getType()).isEqualTo(OrderType.TAKEOUT), - () -> assertThat(order.getOrderDateTime()).isEqualTo(신규_주문.getOrderDateTime()) + () -> assertThat(order.getType()).isEqualTo(OrderType.TAKEOUT) ); } @@ -263,81 +223,84 @@ void createOrderTakeout() { @Test void createOrderDelivery() { //given + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(menuRepository.findAllByIdIn(anyList())).willReturn(Collections.singletonList(뿌링클_세트)); - given(menuRepository.findById(any())).willReturn(Optional.of(뿌링클_세트)); - given(orderRepository.save(any(Order.class))).willReturn(신규_주문); + Order 배달_식사_주문 = 신규_배달_주문(뿌링클_1개, "우리집"); //when - Order order = orderService.create(신규_주문); + Order order = orderService.create(배달_식사_주문); //then assertAll( () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), () -> assertThat(order.getType()).isEqualTo(OrderType.DELIVERY), - () -> assertThat(order.getOrderDateTime()).isEqualTo(신규_주문.getOrderDateTime()) + () -> assertThat(order.getDeliveryAddress()).isEqualTo("우리집") ); } - @DisplayName("주문 수락 예외 - 대기중인 주문만 수락 가능") + @DisplayName("대기중인 주문만 수락할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") - @EnumSource(value = OrderStatus.class, names = {"ACCEPTED", "SERVED", "DELIVERING", "DELIVERED", "COMPLETED"}) + @EnumSource(value = OrderStatus.class, names = {"WAITING"}, mode = Mode.EXCLUDE) void accept(OrderStatus orderStatus) { //given - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 대기중이_아닌_배달_식사_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); //when - ThrowingCallable actual = () -> orderService.accept(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.accept(대기중이_아닌_배달_식사_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); } - @DisplayName("배달 주문 수락") + @DisplayName("대기 중인 배달 주문만 수락할 수 있다.") @Test void acceptOrderDelivery() { //given - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + + Order 대기중인_배달_식사_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집")); //when - Order actual = orderService.accept(신규_주문.getId()); + Order actual = orderService.accept(대기중인_배달_식사_주문.getId()); //then - assertAll( - () -> assertThat(actual.getStatus()).isEqualTo(OrderStatus.ACCEPTED), - () -> verify(kitchenridersClient, atLeastOnce()).requestDelivery(any(), any(), any()) - ); + assertThat(actual.getStatus()).isEqualTo(OrderStatus.ACCEPTED); } - @DisplayName("주문 수락") + @DisplayName("대기 중인 주문만 수락할 수 있다.") @ParameterizedTest(name = "주문 유형: [{arguments}]") @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) void accept(OrderType orderType) { //given - 신규_주문.setType(orderType); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 대기중인_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, OrderStatus.WAITING)); //when - Order actual = orderService.accept(신규_주문.getId()); + Order actual = orderService.accept(대기중인_주문.getId()); //then assertThat(actual.getStatus()).isEqualTo(OrderStatus.ACCEPTED); } - @DisplayName("조리 완료 예외 - 수락된 주문만 가능") + @DisplayName("수락된 주문만 조리 완료할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") - @EnumSource(value = OrderStatus.class, names = {"WAITING", "SERVED", "DELIVERING", "DELIVERED", "COMPLETED"}) + @EnumSource(value = OrderStatus.class, names = {"ACCEPTED"}, mode = Mode.EXCLUDE) void serveException(OrderStatus orderStatus) { //given - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 수락되지_않은_주문 = orderRepository.save(신규_주문(OrderType.EAT_IN, 뿌링클_1개, orderStatus)); //when - ThrowingCallable actual = () -> orderService.serve(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.serve(수락되지_않은_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -347,44 +310,47 @@ void serveException(OrderStatus orderStatus) { @Test void serve() { //given - 신규_주문.setStatus(OrderStatus.ACCEPTED); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 수락된_주문 = orderRepository.save(신규_주문(OrderType.EAT_IN, 뿌링클_1개, OrderStatus.ACCEPTED)); //when - Order actual = orderService.serve(신규_주문.getId()); + Order actual = orderService.serve(수락된_주문.getId()); //then assertThat(actual.getStatus()).isEqualTo(OrderStatus.SERVED); } - @DisplayName("배달 중 예외 - 배달 주문만 가능") + @DisplayName("배달 주문만 배달 시작할 수 있다.") @ParameterizedTest(name = "주문 유형: [{arguments}]") @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) void startDeliveryOrderTypeException(OrderType orderType) { //given - 신규_주문.setType(orderType); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 배달이_아닌_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, OrderStatus.SERVED)); //when - ThrowingCallable actual = () -> orderService.startDelivery(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.startDelivery(배달이_아닌_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); } - @DisplayName("배달 중 예외 - 조리완료된 주문만 가능") + @DisplayName("조리완료된 주문만 배달을 시작할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERING", "DELIVERED", "COMPLETED"}) void startDeliveryOrderStatusException(OrderStatus orderStatus) { //given - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 조리_완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); //when - ThrowingCallable actual = () -> orderService.startDelivery(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.startDelivery(조리_완료되지_않은_배달_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -394,29 +360,30 @@ void startDeliveryOrderStatusException(OrderStatus orderStatus) { @Test void startDelivery() { //given - 신규_주문.setType(OrderType.DELIVERY); - 신규_주문.setStatus(OrderStatus.SERVED); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 조리_완료된_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.SERVED)); //when - Order actual = orderService.startDelivery(신규_주문.getId()); + Order actual = orderService.startDelivery(조리_완료된_배달_주문.getId()); //then assertThat(actual.getStatus()).isEqualTo(OrderStatus.DELIVERING); } - @DisplayName("배달 완료 예외 - 배달중인 주문만 가능") + @DisplayName("배달중인 주문만 가능 배달완료할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERED", "COMPLETED"}) void completeDeliveryOrderStatusException(OrderStatus orderStatus) { //given - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); //when - ThrowingCallable actual = () -> orderService.completeDelivery(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.completeDelivery(배달중인_배달_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -426,30 +393,30 @@ void completeDeliveryOrderStatusException(OrderStatus orderStatus) { @Test void completeDelivery() { //given - 신규_주문.setType(OrderType.DELIVERY); - 신규_주문.setStatus(OrderStatus.DELIVERING); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.DELIVERING)); //when - Order actual = orderService.completeDelivery(신규_주문.getId()); + Order actual = orderService.completeDelivery(배달중인_배달_주문.getId()); //then assertThat(actual.getStatus()).isEqualTo(OrderStatus.DELIVERED); } - @DisplayName("배달 주문 완료 예외 - 배달 완료 주문만 가능") + @DisplayName("배달 완료 주문만 주문 완료할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERING", "COMPLETED"}) void completeDeliveryStatusException(OrderStatus orderStatus) { //given - 신규_주문.setType(OrderType.DELIVERY); - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 배달완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); //when - ThrowingCallable actual = () -> orderService.complete(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.complete(배달완료되지_않은_배달_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -459,47 +426,47 @@ void completeDeliveryStatusException(OrderStatus orderStatus) { @Test void completeDeliveryOrder() { //given - 신규_주문.setType(OrderType.DELIVERY); - 신규_주문.setStatus(OrderStatus.DELIVERED); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 배달완료된_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.DELIVERED)); //when - Order actual = orderService.complete(신규_주문.getId()); + Order actual = orderService.complete(배달완료된_배달_주문.getId()); //then assertThat(actual.getStatus()).isEqualTo(OrderStatus.COMPLETED); } - @DisplayName("포장 주문 완료 예외 - 조리완료된 주문만 가능") + @DisplayName("조리완료된 포장주문만 주문완료할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) void completeTakeoutOrderStatusException(OrderStatus orderStatus) { //given - 신규_주문.setType(OrderType.TAKEOUT); - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 조리완료되지_않은_포장_주문 = orderRepository.save(신규_주문(OrderType.TAKEOUT, 뿌링클_1개, orderStatus)); //when - ThrowingCallable actual = () -> orderService.complete(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.complete(조리완료되지_않은_포장_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); } - @DisplayName("매장 주문 완료 예외 - 조리완료된 주문만 가능") + @DisplayName("조리완료된 매장주문만 주문완료할 수 있다.") @ParameterizedTest(name = "주문 상태: [{arguments}]") @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) void completeEatInStatusException(OrderStatus orderStatus) { //given - 신규_주문.setType(OrderType.EAT_IN); - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 조리완료되지_않은_매장_주문 = orderRepository.save(신규_주문(OrderType.TAKEOUT, 뿌링클_1개, orderStatus)); //when - ThrowingCallable actual = () -> orderService.complete(신규_주문.getId()); + ThrowingCallable actual = () -> orderService.complete(조리완료되지_않은_매장_주문.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -510,13 +477,13 @@ void completeEatInStatusException(OrderStatus orderStatus) { @MethodSource("completeTakeoutOrDelivery") void completeTakeoutOrDeliveryOrder(OrderType orderType, OrderStatus orderStatus) { //given - 신규_주문.setType(orderType); - 신규_주문.setStatus(orderStatus); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); + Order 조리완료된_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, orderStatus)); //when - Order actual = orderService.complete(신규_주문.getId()); + Order actual = orderService.complete(조리완료된_주문.getId()); //then assertThat(actual.getStatus()).isEqualTo(OrderStatus.COMPLETED); @@ -533,14 +500,18 @@ private static Stream completeTakeoutOrDelivery() { @Test void completeEatInOrder() { //given - 신규_주문.setType(OrderType.EAT_IN); - 신규_주문.setStatus(OrderStatus.SERVED); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + + OrderTable orderTable = orderTableRepository.save(착석한_식탁()); + Order 신규_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개, OrderStatus.SERVED); + 신규_주문.setOrderTableId(orderTable.getId()); + 신규_주문.setOrderTable(orderTable); - given(orderRepository.findById(any(UUID.class))).willReturn(Optional.of(신규_주문)); - given(orderRepository.existsByOrderTableAndStatusNot(any(), any())).willReturn(true); + Order 조리완료된_주문 = orderRepository.save(신규_주문); //when - Order actual = orderService.complete(신규_주문.getId()); + Order actual = orderService.complete(조리완료된_주문.getId()); //then assertAll( @@ -554,7 +525,16 @@ void completeEatInOrder() { @Test void findAll() { //given - given(orderRepository.findAll()).willReturn(Arrays.asList(배달_주문, 포장_주문, 매장_주문)); + Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); + List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + + Order 매장_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); + Order 포장_주문 = 신규_주문(OrderType.TAKEOUT, 뿌링클_1개); + Order 배달_주문 = 신규_주문(OrderType.DELIVERY, 뿌링클_1개); + + orderRepository.save(매장_주문); + orderRepository.save(포장_주문); + orderRepository.save(배달_주문); //when List actual = orderService.findAll(); @@ -563,4 +543,64 @@ void findAll() { assertThat(actual).hasSize(3); } + private OrderTable 착석한_식탁() { + OrderTable orderTable = new OrderTable(); + orderTable.setEmpty(false); + return orderTable; + } + + private Menu 뿌링클_세트() { + Menu menu = new Menu(); + menu.setDisplayed(true); + menu.setPrice(BigDecimal.valueOf(10_000)); + return menu; + } + + private Order 신규_주문(OrderType orderType, List orderLineItems) { + return 신규_주문(orderType, orderLineItems, OrderStatus.WAITING); + } + + private Order 신규_주문(OrderType orderType, List orderLineItems, OrderStatus orderStatus) { + Order order = new Order(); + order.setType(orderType); + order.setOrderLineItems(orderLineItems); + order.setStatus(orderStatus); + return order; + } + + private Order 신규_배달_주문(List orderLineItems, String deliveryAddress, OrderStatus orderStatus) { + Order order = 신규_주문(OrderType.DELIVERY, orderLineItems, orderStatus); + order.setDeliveryAddress(deliveryAddress); + return order; + } + + private Order 신규_배달_주문(List orderLineItems, String deliveryAddress) { + return 신규_배달_주문(orderLineItems, deliveryAddress, OrderStatus.WAITING); + } + + private Order 신규_배달_주문(List orderLineItems) { + return 신규_배달_주문(orderLineItems, "독도"); + } + + public static OrderLineItem 주문_항목_1개(Menu menu) { + return 주문_항목(menu, 1); + } + + public static OrderLineItem 주문_항목_1개(Menu menu, int price) { + return 주문_항목(menu, 1, price); + } + + public static OrderLineItem 주문_항목(Menu menu, int quantity) { + return 주문_항목(menu, quantity, 10_000); + } + + public static OrderLineItem 주문_항목(Menu menu, int quantity, int price) { + OrderLineItem orderLineItem = new OrderLineItem(); + orderLineItem.setMenu(menu); + orderLineItem.setMenuId(menu.getId()); + orderLineItem.setQuantity(quantity); + orderLineItem.setPrice(BigDecimal.valueOf(price)); + return orderLineItem; + } + } From 46627e84b191c59c03579d5c172605dc5b986fe2 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 19 Mar 2022 18:52:31 +0900 Subject: [PATCH 17/40] =?UTF-8?q?test:=20=EC=83=81=ED=92=88=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kitchenpos/application/ProductServiceTest.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/java/kitchenpos/application/ProductServiceTest.java b/src/test/java/kitchenpos/application/ProductServiceTest.java index ba591d0ec..fd79ba8a1 100644 --- a/src/test/java/kitchenpos/application/ProductServiceTest.java +++ b/src/test/java/kitchenpos/application/ProductServiceTest.java @@ -14,6 +14,7 @@ import java.util.NoSuchElementException; import java.util.UUID; import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuProduct; import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; @@ -79,18 +80,23 @@ void createNameException(String name) { }) void changePrice(long price, boolean expectedDisplayed) { //given - productRepository.save(뿌링클); + Product 신규_상품 = productRepository.save(상품_생성(12_000)); + + MenuProduct menuProduct = new MenuProduct(); + menuProduct.setProduct(신규_상품); + menuProduct.setProductId(신규_상품.getId()); + menuProduct.setQuantity(1); Menu menu = new Menu(); menu.setDisplayed(true); - menu.setMenuProducts(Arrays.asList(뿌링클_1개, 콜라_1개)); + menu.setMenuProducts(Arrays.asList(menuProduct, 콜라_1개)); menu.setPrice(BigDecimal.valueOf(11_000L)); menuRepository.save(menu); Product 변경할_금액 = 상품_생성(price); //when - Product product = productService.changePrice(뿌링클.getId(), 변경할_금액); + Product product = productService.changePrice(신규_상품.getId(), 변경할_금액); //then assertAll( From a3a04094ab1521bf93ec5cedee4f6379a81cdf76 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 19 Mar 2022 18:58:04 +0900 Subject: [PATCH 18/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20controller=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/DefaultMenuGroupService.java | 38 +++++++++++++++++++ .../application/MenuGroupService.java | 32 ++-------------- ....java => DefaultMenuGroupServiceTest.java} | 6 +-- .../kitchenpos/ui/FakeMenuGroupService.java | 24 ++++++++++++ .../ui/MenuGroupRestControllerTest.java | 19 ++-------- .../kitchenpos/ui/MenuGroupTestConfig.java | 14 +++++++ 6 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 src/main/java/kitchenpos/application/DefaultMenuGroupService.java rename src/test/java/kitchenpos/application/{MenuGroupServiceTest.java => DefaultMenuGroupServiceTest.java} (93%) create mode 100644 src/test/java/kitchenpos/ui/FakeMenuGroupService.java create mode 100644 src/test/java/kitchenpos/ui/MenuGroupTestConfig.java diff --git a/src/main/java/kitchenpos/application/DefaultMenuGroupService.java b/src/main/java/kitchenpos/application/DefaultMenuGroupService.java new file mode 100644 index 000000000..165973767 --- /dev/null +++ b/src/main/java/kitchenpos/application/DefaultMenuGroupService.java @@ -0,0 +1,38 @@ +package kitchenpos.application; + +import kitchenpos.domain.MenuGroup; +import kitchenpos.domain.MenuGroupRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@Service +public class DefaultMenuGroupService implements MenuGroupService { + private final MenuGroupRepository menuGroupRepository; + + public DefaultMenuGroupService(final MenuGroupRepository menuGroupRepository) { + this.menuGroupRepository = menuGroupRepository; + } + + @Override + @Transactional + public MenuGroup create(final MenuGroup request) { + final String name = request.getName(); + if (Objects.isNull(name) || name.isEmpty()) { + throw new IllegalArgumentException(); + } + final MenuGroup menuGroup = new MenuGroup(); + menuGroup.setId(UUID.randomUUID()); + menuGroup.setName(name); + return menuGroupRepository.save(menuGroup); + } + + @Override + @Transactional(readOnly = true) + public List findAll() { + return menuGroupRepository.findAll(); + } +} diff --git a/src/main/java/kitchenpos/application/MenuGroupService.java b/src/main/java/kitchenpos/application/MenuGroupService.java index 84add81f5..7963d96e6 100644 --- a/src/main/java/kitchenpos/application/MenuGroupService.java +++ b/src/main/java/kitchenpos/application/MenuGroupService.java @@ -1,36 +1,12 @@ package kitchenpos.application; -import kitchenpos.domain.MenuGroup; -import kitchenpos.domain.MenuGroupRepository; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.util.List; -import java.util.Objects; -import java.util.UUID; +import kitchenpos.domain.MenuGroup; -@Service -public class MenuGroupService { - private final MenuGroupRepository menuGroupRepository; +public interface MenuGroupService { - public MenuGroupService(final MenuGroupRepository menuGroupRepository) { - this.menuGroupRepository = menuGroupRepository; - } + MenuGroup create(final MenuGroup request); - @Transactional - public MenuGroup create(final MenuGroup request) { - final String name = request.getName(); - if (Objects.isNull(name) || name.isEmpty()) { - throw new IllegalArgumentException(); - } - final MenuGroup menuGroup = new MenuGroup(); - menuGroup.setId(UUID.randomUUID()); - menuGroup.setName(name); - return menuGroupRepository.save(menuGroup); - } + List findAll(); - @Transactional(readOnly = true) - public List findAll() { - return menuGroupRepository.findAll(); - } } diff --git a/src/test/java/kitchenpos/application/MenuGroupServiceTest.java b/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java similarity index 93% rename from src/test/java/kitchenpos/application/MenuGroupServiceTest.java rename to src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java index 8e824aba8..d0c485234 100644 --- a/src/test/java/kitchenpos/application/MenuGroupServiceTest.java +++ b/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java @@ -17,14 +17,14 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; @DisplayName("메뉴 그룹") -class MenuGroupServiceTest { +class DefaultMenuGroupServiceTest { private final MenuGroupRepository menuGroupRepository = new InMemoryMenuGroupRepository(); - private MenuGroupService menuGroupService; + private DefaultMenuGroupService menuGroupService; @BeforeEach void setUp() { - menuGroupService = new MenuGroupService(menuGroupRepository); + menuGroupService = new DefaultMenuGroupService(menuGroupRepository); } @DisplayName("이름이 없으면 예외 발생") diff --git a/src/test/java/kitchenpos/ui/FakeMenuGroupService.java b/src/test/java/kitchenpos/ui/FakeMenuGroupService.java new file mode 100644 index 000000000..141a16e58 --- /dev/null +++ b/src/test/java/kitchenpos/ui/FakeMenuGroupService.java @@ -0,0 +1,24 @@ +package kitchenpos.ui; + +import static kitchenpos.application.MenuGroupFixture.세트메뉴; +import static kitchenpos.application.MenuGroupFixture.추천메뉴; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import kitchenpos.application.MenuGroupService; +import kitchenpos.domain.MenuGroup; + +public class FakeMenuGroupService implements MenuGroupService { + + @Override + public MenuGroup create(MenuGroup request) { + request.setId(UUID.randomUUID()); + return request; + } + + @Override + public List findAll() { + return Arrays.asList(세트메뉴, 추천메뉴); + } +} diff --git a/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java b/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java index 0cdc26860..38f59ebdd 100644 --- a/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java +++ b/src/test/java/kitchenpos/ui/MenuGroupRestControllerTest.java @@ -1,10 +1,7 @@ package kitchenpos.ui; -import static kitchenpos.application.MenuGroupFixture.메뉴판; import static kitchenpos.application.MenuGroupFixture.세트메뉴; import static kitchenpos.application.MenuGroupFixture.추천메뉴; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -12,18 +9,18 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import kitchenpos.application.MenuGroupService; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @DisplayName("메뉴 그룹 관리") @WebMvcTest(MenuGroupRestController.class) +@Import(MenuGroupTestConfig.class) class MenuGroupRestControllerTest { private static final String MENU_GROUPS_URI = "/api/menu-groups"; @@ -34,17 +31,12 @@ class MenuGroupRestControllerTest { @Autowired private ObjectMapper objectMapper; - @MockBean - private MenuGroupService menuGroupService; - - @DisplayName("메뉴그룹 생성") + @DisplayName("메뉴 그룹을 생성할 수 있다.") @Test void create() throws Exception { //given String body = objectMapper.writeValueAsString(세트메뉴); - given(menuGroupService.create(any())).willReturn(세트메뉴); - //when ResultActions resultActions = 그룹_생성_요청(body); @@ -55,12 +47,9 @@ void create() throws Exception { .andExpect(jsonPath("$.name").value(세트메뉴.getName())); } - @DisplayName("메뉴그룹 조회") + @DisplayName("등록된 모든 메뉴 그룹을 조회할 수 있다.") @Test void findAll() throws Exception { - //given - given(menuGroupService.findAll()).willReturn(메뉴판); - //when ResultActions resultActions = 그룹_조회_요청(); diff --git a/src/test/java/kitchenpos/ui/MenuGroupTestConfig.java b/src/test/java/kitchenpos/ui/MenuGroupTestConfig.java new file mode 100644 index 000000000..02865011f --- /dev/null +++ b/src/test/java/kitchenpos/ui/MenuGroupTestConfig.java @@ -0,0 +1,14 @@ +package kitchenpos.ui; + +import kitchenpos.application.MenuGroupService; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class MenuGroupTestConfig { + + @Bean + public MenuGroupService menuGroupService() { + return new FakeMenuGroupService(); + } +} From 915544b6738fff72f64e14ec58364ec8d8239d14 Mon Sep 17 00:00:00 2001 From: yongju Date: Sat, 19 Mar 2022 19:10:27 +0900 Subject: [PATCH 19/40] =?UTF-8?q?test:=20=EC=A3=BC=EB=AC=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/OrderServiceTest.java | 78 +++++++------------ 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/src/test/java/kitchenpos/application/OrderServiceTest.java b/src/test/java/kitchenpos/application/OrderServiceTest.java index 8906b0976..34e64d12c 100644 --- a/src/test/java/kitchenpos/application/OrderServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderServiceTest.java @@ -113,8 +113,7 @@ void createOrderInvalidQuantityException(OrderType orderType) { @Test void createOrderNotDisplayedMenuException() { //given - Menu 진열되지_않은_메뉴 = menuRepository.save(new Menu()); - List 진열되지_않은_메뉴_상품 = Collections.singletonList(주문_항목_1개(진열되지_않은_메뉴)); + List 진열되지_않은_메뉴_상품 = 메뉴_뿌링클_1개(new Menu()); Order 진열되지_않은_상품_주문 = 신규_배달_주문(진열되지_않은_메뉴_상품); //when @@ -145,9 +144,7 @@ void createOrderMismatchPriceException() { @NullAndEmptySource void createDeliveryOrderHasNoAddressException(String deliveryAddress) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 주소_없는_배달_주문 = 신규_배달_주문(뿌링클_1개, deliveryAddress); //when @@ -161,9 +158,7 @@ void createDeliveryOrderHasNoAddressException(String deliveryAddress) { @Test void createEatInException() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 착석하지_않고_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); OrderTable orderTable1 = new OrderTable(); orderTable1.setEmpty(true); @@ -182,8 +177,7 @@ void createEatInException() { @Test void createOrderEatIn() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); OrderTable orderTable = orderTableRepository.save(착석한_식탁()); Order 매장_식사_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); @@ -204,8 +198,7 @@ void createOrderEatIn() { @Test void createOrderTakeout() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 포장_식사_주문 = 신규_주문(OrderType.TAKEOUT, 뿌링클_1개); @@ -223,8 +216,7 @@ void createOrderTakeout() { @Test void createOrderDelivery() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 배달_식사_주문 = 신규_배달_주문(뿌링클_1개, "우리집"); @@ -244,8 +236,7 @@ void createOrderDelivery() { @EnumSource(value = OrderStatus.class, names = {"WAITING"}, mode = Mode.EXCLUDE) void accept(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 대기중이_아닌_배달_식사_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); @@ -260,8 +251,7 @@ void accept(OrderStatus orderStatus) { @Test void acceptOrderDelivery() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 대기중인_배달_식사_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집")); @@ -277,8 +267,7 @@ void acceptOrderDelivery() { @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) void accept(OrderType orderType) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 대기중인_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, OrderStatus.WAITING)); @@ -294,8 +283,7 @@ void accept(OrderType orderType) { @EnumSource(value = OrderStatus.class, names = {"ACCEPTED"}, mode = Mode.EXCLUDE) void serveException(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 수락되지_않은_주문 = orderRepository.save(신규_주문(OrderType.EAT_IN, 뿌링클_1개, orderStatus)); @@ -310,8 +298,7 @@ void serveException(OrderStatus orderStatus) { @Test void serve() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 수락된_주문 = orderRepository.save(신규_주문(OrderType.EAT_IN, 뿌링클_1개, OrderStatus.ACCEPTED)); @@ -327,8 +314,7 @@ void serve() { @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) void startDeliveryOrderTypeException(OrderType orderType) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 배달이_아닌_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, OrderStatus.SERVED)); @@ -344,8 +330,7 @@ void startDeliveryOrderTypeException(OrderType orderType) { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERING", "DELIVERED", "COMPLETED"}) void startDeliveryOrderStatusException(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 조리_완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); @@ -360,8 +345,7 @@ void startDeliveryOrderStatusException(OrderStatus orderStatus) { @Test void startDelivery() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 조리_완료된_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.SERVED)); @@ -377,8 +361,7 @@ void startDelivery() { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERED", "COMPLETED"}) void completeDeliveryOrderStatusException(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); @@ -393,8 +376,7 @@ void completeDeliveryOrderStatusException(OrderStatus orderStatus) { @Test void completeDelivery() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.DELIVERING)); @@ -410,8 +392,7 @@ void completeDelivery() { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERING", "COMPLETED"}) void completeDeliveryStatusException(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 배달완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); @@ -426,8 +407,7 @@ void completeDeliveryStatusException(OrderStatus orderStatus) { @Test void completeDeliveryOrder() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 배달완료된_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.DELIVERED)); @@ -443,8 +423,7 @@ void completeDeliveryOrder() { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) void completeTakeoutOrderStatusException(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 조리완료되지_않은_포장_주문 = orderRepository.save(신규_주문(OrderType.TAKEOUT, 뿌링클_1개, orderStatus)); @@ -460,8 +439,7 @@ void completeTakeoutOrderStatusException(OrderStatus orderStatus) { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) void completeEatInStatusException(OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 조리완료되지_않은_매장_주문 = orderRepository.save(신규_주문(OrderType.TAKEOUT, 뿌링클_1개, orderStatus)); @@ -477,8 +455,7 @@ void completeEatInStatusException(OrderStatus orderStatus) { @MethodSource("completeTakeoutOrDelivery") void completeTakeoutOrDeliveryOrder(OrderType orderType, OrderStatus orderStatus) { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 조리완료된_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, orderStatus)); @@ -500,11 +477,10 @@ private static Stream completeTakeoutOrDelivery() { @Test void completeEatInOrder() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - OrderTable orderTable = orderTableRepository.save(착석한_식탁()); Order 신규_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개, OrderStatus.SERVED); + OrderTable orderTable = orderTableRepository.save(착석한_식탁()); 신규_주문.setOrderTableId(orderTable.getId()); 신규_주문.setOrderTable(orderTable); @@ -521,12 +497,16 @@ void completeEatInOrder() { ); } + private List 메뉴_뿌링클_1개(Menu menu) { + Menu 뿌링클_세트 = menuRepository.save(menu); + return Collections.singletonList(주문_항목_1개(뿌링클_세트)); + } + @DisplayName("모든 주문 조회") @Test void findAll() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 뿌링클_1개 = Collections.singletonList(주문_항목_1개(뿌링클_세트)); + List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); Order 매장_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); Order 포장_주문 = 신규_주문(OrderType.TAKEOUT, 뿌링클_1개); From 44380f776ff6047edf26f3d8d8a14d32bd88ca9f Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 07:47:22 +0900 Subject: [PATCH 20/40] =?UTF-8?q?refactor:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kitchenpos/application/OrderService.java | 49 +++---------------- .../OrderDeliveryAddressException.java | 8 +++ .../exception/OrderDisplayException.java | 8 +++ .../OrderInvalidQuantityException.java | 8 +++ .../OrderLineItemNotExistException.java | 8 +++ .../OrderLineItemNotMatchException.java | 8 +++ .../OrderLineItemPriceException.java | 8 +++ .../exception/OrderTypeNotExistException.java | 8 +++ .../application/OrderServiceTest.java | 14 +++--- 9 files changed, 70 insertions(+), 49 deletions(-) create mode 100644 src/main/java/kitchenpos/domain/exception/OrderDeliveryAddressException.java create mode 100644 src/main/java/kitchenpos/domain/exception/OrderDisplayException.java create mode 100644 src/main/java/kitchenpos/domain/exception/OrderInvalidQuantityException.java create mode 100644 src/main/java/kitchenpos/domain/exception/OrderLineItemNotExistException.java create mode 100644 src/main/java/kitchenpos/domain/exception/OrderLineItemNotMatchException.java create mode 100644 src/main/java/kitchenpos/domain/exception/OrderLineItemPriceException.java create mode 100644 src/main/java/kitchenpos/domain/exception/OrderTypeNotExistException.java diff --git a/src/main/java/kitchenpos/application/OrderService.java b/src/main/java/kitchenpos/application/OrderService.java index 626fc6cdf..e4110e357 100644 --- a/src/main/java/kitchenpos/application/OrderService.java +++ b/src/main/java/kitchenpos/application/OrderService.java @@ -1,6 +1,13 @@ package kitchenpos.application; import kitchenpos.domain.*; +import kitchenpos.domain.exception.OrderDeliveryAddressException; +import kitchenpos.domain.exception.OrderDisplayException; +import kitchenpos.domain.exception.OrderInvalidQuantityException; +import kitchenpos.domain.exception.OrderLineItemNotExistException; +import kitchenpos.domain.exception.OrderLineItemNotMatchException; +import kitchenpos.domain.exception.OrderLineItemPriceException; +import kitchenpos.domain.exception.OrderTypeNotExistException; import kitchenpos.infra.KitchenridersClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -181,46 +188,4 @@ public List findAll() { return orderRepository.findAll(); } - - static class OrderTypeNotExistException extends IllegalStateException { - public OrderTypeNotExistException() { - super("주문 유형이 올바르지 않습니다"); - } - } - - static class OrderLineItemNotExistException extends IllegalStateException { - public OrderLineItemNotExistException() { - super("주문 상품이 없습니다."); - } - } - - static class OrderLineItemNotMatchException extends IllegalStateException { - public OrderLineItemNotMatchException() { - super("등록되지 않은 메뉴는 주문할 수 없습니다."); - } - } - - static class OrderInvalidQuantityException extends IllegalStateException { - public OrderInvalidQuantityException(long quantity) { - super("최소 주문 수량은 0개 이상입니다. 주문 수량 : " + quantity); - } - } - - static class OrderDisplayException extends IllegalStateException { - public OrderDisplayException() { - super("진열되지 않은 메뉴는 주문할 수 없습니다."); - } - } - - static class OrderLineItemPriceException extends IllegalArgumentException { - public OrderLineItemPriceException(String menu, long menuPrice, long requestPrice) { - super("가격이 일치하지 않습니다. 메뉴명: " + menu + ", 메뉴 가격: " + menuPrice + ", 지불 가격: " + requestPrice); - } - } - - static class OrderDeliveryAddressException extends IllegalArgumentException { - public OrderDeliveryAddressException() { - super("배달 주소가 없습니다."); - } - } } diff --git a/src/main/java/kitchenpos/domain/exception/OrderDeliveryAddressException.java b/src/main/java/kitchenpos/domain/exception/OrderDeliveryAddressException.java new file mode 100644 index 000000000..2074eb200 --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderDeliveryAddressException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderDeliveryAddressException extends IllegalArgumentException { + + public OrderDeliveryAddressException() { + super("배달 주소가 없습니다."); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/OrderDisplayException.java b/src/main/java/kitchenpos/domain/exception/OrderDisplayException.java new file mode 100644 index 000000000..844ee2c35 --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderDisplayException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderDisplayException extends IllegalStateException { + + public OrderDisplayException() { + super("진열되지 않은 메뉴는 주문할 수 없습니다."); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/OrderInvalidQuantityException.java b/src/main/java/kitchenpos/domain/exception/OrderInvalidQuantityException.java new file mode 100644 index 000000000..35ab58435 --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderInvalidQuantityException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderInvalidQuantityException extends IllegalStateException { + + public OrderInvalidQuantityException(long quantity) { + super("최소 주문 수량은 0개 이상입니다. 주문 수량 : " + quantity); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/OrderLineItemNotExistException.java b/src/main/java/kitchenpos/domain/exception/OrderLineItemNotExistException.java new file mode 100644 index 000000000..9fe210c88 --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderLineItemNotExistException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderLineItemNotExistException extends IllegalStateException { + + public OrderLineItemNotExistException() { + super("주문 상품이 없습니다."); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/OrderLineItemNotMatchException.java b/src/main/java/kitchenpos/domain/exception/OrderLineItemNotMatchException.java new file mode 100644 index 000000000..361acf201 --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderLineItemNotMatchException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderLineItemNotMatchException extends IllegalStateException { + + public OrderLineItemNotMatchException() { + super("등록되지 않은 메뉴는 주문할 수 없습니다."); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/OrderLineItemPriceException.java b/src/main/java/kitchenpos/domain/exception/OrderLineItemPriceException.java new file mode 100644 index 000000000..b03f54a6c --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderLineItemPriceException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderLineItemPriceException extends IllegalArgumentException { + + public OrderLineItemPriceException(String menu, long menuPrice, long requestPrice) { + super("가격이 일치하지 않습니다. 메뉴명: " + menu + ", 메뉴 가격: " + menuPrice + ", 지불 가격: " + requestPrice); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/OrderTypeNotExistException.java b/src/main/java/kitchenpos/domain/exception/OrderTypeNotExistException.java new file mode 100644 index 000000000..875dd876a --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderTypeNotExistException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class OrderTypeNotExistException extends IllegalStateException { + + public OrderTypeNotExistException() { + super("주문 유형이 올바르지 않습니다"); + } +} diff --git a/src/test/java/kitchenpos/application/OrderServiceTest.java b/src/test/java/kitchenpos/application/OrderServiceTest.java index 34e64d12c..039fafe98 100644 --- a/src/test/java/kitchenpos/application/OrderServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderServiceTest.java @@ -9,13 +9,6 @@ import java.util.Collections; import java.util.List; import java.util.stream.Stream; -import kitchenpos.application.OrderService.OrderDeliveryAddressException; -import kitchenpos.application.OrderService.OrderDisplayException; -import kitchenpos.application.OrderService.OrderInvalidQuantityException; -import kitchenpos.application.OrderService.OrderLineItemNotExistException; -import kitchenpos.application.OrderService.OrderLineItemNotMatchException; -import kitchenpos.application.OrderService.OrderLineItemPriceException; -import kitchenpos.application.OrderService.OrderTypeNotExistException; import kitchenpos.domain.Menu; import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Order; @@ -25,6 +18,13 @@ import kitchenpos.domain.OrderTable; import kitchenpos.domain.OrderTableRepository; import kitchenpos.domain.OrderType; +import kitchenpos.domain.exception.OrderDeliveryAddressException; +import kitchenpos.domain.exception.OrderDisplayException; +import kitchenpos.domain.exception.OrderInvalidQuantityException; +import kitchenpos.domain.exception.OrderLineItemNotExistException; +import kitchenpos.domain.exception.OrderLineItemNotMatchException; +import kitchenpos.domain.exception.OrderLineItemPriceException; +import kitchenpos.domain.exception.OrderTypeNotExistException; import kitchenpos.infra.KitchenridersClient; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeEach; From f2dfbf541040a363c373210343253d39eeba0bcb Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 07:53:21 +0900 Subject: [PATCH 21/40] =?UTF-8?q?refactor:=20repository=20interface=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/kitchenpos/domain/JpaMenuGroupRepository.java | 8 ++++++++ src/main/java/kitchenpos/domain/JpaMenuRepository.java | 8 ++++++++ src/main/java/kitchenpos/domain/JpaOrderRepository.java | 8 ++++++++ .../java/kitchenpos/domain/JpaOrderTableRepository.java | 8 ++++++++ src/main/java/kitchenpos/domain/JpaProductRepository.java | 8 ++++++++ src/main/java/kitchenpos/domain/MenuGroupRepository.java | 3 --- src/main/java/kitchenpos/domain/MenuRepository.java | 3 --- src/main/java/kitchenpos/domain/OrderRepository.java | 3 --- src/main/java/kitchenpos/domain/OrderTableRepository.java | 3 --- src/main/java/kitchenpos/domain/ProductRepository.java | 3 --- 10 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 src/main/java/kitchenpos/domain/JpaMenuGroupRepository.java create mode 100644 src/main/java/kitchenpos/domain/JpaMenuRepository.java create mode 100644 src/main/java/kitchenpos/domain/JpaOrderRepository.java create mode 100644 src/main/java/kitchenpos/domain/JpaOrderTableRepository.java create mode 100644 src/main/java/kitchenpos/domain/JpaProductRepository.java diff --git a/src/main/java/kitchenpos/domain/JpaMenuGroupRepository.java b/src/main/java/kitchenpos/domain/JpaMenuGroupRepository.java new file mode 100644 index 000000000..1752fc1e4 --- /dev/null +++ b/src/main/java/kitchenpos/domain/JpaMenuGroupRepository.java @@ -0,0 +1,8 @@ +package kitchenpos.domain; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +interface JpaMenuGroupRepository extends MenuGroupRepository, JpaRepository { + +} diff --git a/src/main/java/kitchenpos/domain/JpaMenuRepository.java b/src/main/java/kitchenpos/domain/JpaMenuRepository.java new file mode 100644 index 000000000..1f3f51dbc --- /dev/null +++ b/src/main/java/kitchenpos/domain/JpaMenuRepository.java @@ -0,0 +1,8 @@ +package kitchenpos.domain; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +interface JpaMenuRepository extends MenuRepository, JpaRepository { + +} diff --git a/src/main/java/kitchenpos/domain/JpaOrderRepository.java b/src/main/java/kitchenpos/domain/JpaOrderRepository.java new file mode 100644 index 000000000..b82636f53 --- /dev/null +++ b/src/main/java/kitchenpos/domain/JpaOrderRepository.java @@ -0,0 +1,8 @@ +package kitchenpos.domain; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +interface JpaOrderRepository extends OrderRepository, JpaRepository { + +} diff --git a/src/main/java/kitchenpos/domain/JpaOrderTableRepository.java b/src/main/java/kitchenpos/domain/JpaOrderTableRepository.java new file mode 100644 index 000000000..d44c7df6a --- /dev/null +++ b/src/main/java/kitchenpos/domain/JpaOrderTableRepository.java @@ -0,0 +1,8 @@ +package kitchenpos.domain; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +interface JpaOrderTableRepository extends OrderTableRepository, JpaRepository { + +} diff --git a/src/main/java/kitchenpos/domain/JpaProductRepository.java b/src/main/java/kitchenpos/domain/JpaProductRepository.java new file mode 100644 index 000000000..90b560fbb --- /dev/null +++ b/src/main/java/kitchenpos/domain/JpaProductRepository.java @@ -0,0 +1,8 @@ +package kitchenpos.domain; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +interface JpaProductRepository extends ProductRepository, JpaRepository { + +} diff --git a/src/main/java/kitchenpos/domain/MenuGroupRepository.java b/src/main/java/kitchenpos/domain/MenuGroupRepository.java index d6d238e07..19b7584c1 100644 --- a/src/main/java/kitchenpos/domain/MenuGroupRepository.java +++ b/src/main/java/kitchenpos/domain/MenuGroupRepository.java @@ -15,6 +15,3 @@ public interface MenuGroupRepository { Optional findById(UUID menuGroupId); } -interface JpaMenuGroupRepository extends MenuGroupRepository, JpaRepository { - -} diff --git a/src/main/java/kitchenpos/domain/MenuRepository.java b/src/main/java/kitchenpos/domain/MenuRepository.java index 22bec5b43..d273172b9 100644 --- a/src/main/java/kitchenpos/domain/MenuRepository.java +++ b/src/main/java/kitchenpos/domain/MenuRepository.java @@ -22,6 +22,3 @@ public interface MenuRepository { } -interface JpaMenuRepository extends MenuRepository, JpaRepository { - -} diff --git a/src/main/java/kitchenpos/domain/OrderRepository.java b/src/main/java/kitchenpos/domain/OrderRepository.java index 94f92b8a0..1456d0047 100644 --- a/src/main/java/kitchenpos/domain/OrderRepository.java +++ b/src/main/java/kitchenpos/domain/OrderRepository.java @@ -16,6 +16,3 @@ public interface OrderRepository { List findAll(); } -interface JpaOrderRepository extends OrderRepository, JpaRepository { - -} diff --git a/src/main/java/kitchenpos/domain/OrderTableRepository.java b/src/main/java/kitchenpos/domain/OrderTableRepository.java index cfa8e5d70..20cef48e6 100644 --- a/src/main/java/kitchenpos/domain/OrderTableRepository.java +++ b/src/main/java/kitchenpos/domain/OrderTableRepository.java @@ -15,6 +15,3 @@ public interface OrderTableRepository { List findAll(); } -interface JpaOrderTableRepository extends OrderTableRepository, JpaRepository { - -} diff --git a/src/main/java/kitchenpos/domain/ProductRepository.java b/src/main/java/kitchenpos/domain/ProductRepository.java index dad74fd84..eff9415d9 100644 --- a/src/main/java/kitchenpos/domain/ProductRepository.java +++ b/src/main/java/kitchenpos/domain/ProductRepository.java @@ -16,6 +16,3 @@ public interface ProductRepository { List findAll(); } -interface JpaProductRepository extends ProductRepository, JpaRepository { - -} From e6b68b3612e8e91a84af94b491b6ac4a873edf61 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 07:55:47 +0900 Subject: [PATCH 22/40] =?UTF-8?q?style:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kitchenpos/domain/MenuGroupRepository.java | 2 -- src/main/java/kitchenpos/domain/MenuRepository.java | 6 ++---- src/main/java/kitchenpos/domain/OrderRepository.java | 2 -- src/main/java/kitchenpos/domain/OrderTableRepository.java | 2 -- src/main/java/kitchenpos/domain/ProductRepository.java | 4 +--- 5 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/main/java/kitchenpos/domain/MenuGroupRepository.java b/src/main/java/kitchenpos/domain/MenuGroupRepository.java index 19b7584c1..8691dd837 100644 --- a/src/main/java/kitchenpos/domain/MenuGroupRepository.java +++ b/src/main/java/kitchenpos/domain/MenuGroupRepository.java @@ -2,9 +2,7 @@ import java.util.List; import java.util.Optional; - import java.util.UUID; -import org.springframework.data.jpa.repository.JpaRepository; public interface MenuGroupRepository { diff --git a/src/main/java/kitchenpos/domain/MenuRepository.java b/src/main/java/kitchenpos/domain/MenuRepository.java index d273172b9..056405e12 100644 --- a/src/main/java/kitchenpos/domain/MenuRepository.java +++ b/src/main/java/kitchenpos/domain/MenuRepository.java @@ -1,13 +1,11 @@ package kitchenpos.domain; +import java.util.List; import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; +import java.util.UUID; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; -import java.util.UUID; - public interface MenuRepository { List findAllByIdIn(List ids); diff --git a/src/main/java/kitchenpos/domain/OrderRepository.java b/src/main/java/kitchenpos/domain/OrderRepository.java index 1456d0047..57fd7eb14 100644 --- a/src/main/java/kitchenpos/domain/OrderRepository.java +++ b/src/main/java/kitchenpos/domain/OrderRepository.java @@ -2,8 +2,6 @@ import java.util.List; import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.UUID; public interface OrderRepository { diff --git a/src/main/java/kitchenpos/domain/OrderTableRepository.java b/src/main/java/kitchenpos/domain/OrderTableRepository.java index 20cef48e6..5a9679432 100644 --- a/src/main/java/kitchenpos/domain/OrderTableRepository.java +++ b/src/main/java/kitchenpos/domain/OrderTableRepository.java @@ -2,8 +2,6 @@ import java.util.List; import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.UUID; public interface OrderTableRepository { diff --git a/src/main/java/kitchenpos/domain/ProductRepository.java b/src/main/java/kitchenpos/domain/ProductRepository.java index eff9415d9..7e72522f4 100644 --- a/src/main/java/kitchenpos/domain/ProductRepository.java +++ b/src/main/java/kitchenpos/domain/ProductRepository.java @@ -1,9 +1,7 @@ package kitchenpos.domain; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.List; +import java.util.Optional; import java.util.UUID; public interface ProductRepository { From f4eac1f91704d53d01d0cf756c3d27630089dd44 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 08:12:07 +0900 Subject: [PATCH 23/40] =?UTF-8?q?refactor:=20list=EC=9D=98=20element=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=8B=9C=20containsExactlyInAnyOrder()=20?= =?UTF-8?q?=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 순서와 상관없이 elements 일치 여부를 검증할 수 있다. --- .../kitchenpos/application/DefaultMenuGroupServiceTest.java | 5 ++--- .../java/kitchenpos/application/OrderTableServiceTest.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java b/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java index d0c485234..4944a10d4 100644 --- a/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java +++ b/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java @@ -20,7 +20,7 @@ class DefaultMenuGroupServiceTest { private final MenuGroupRepository menuGroupRepository = new InMemoryMenuGroupRepository(); - private DefaultMenuGroupService menuGroupService; + private MenuGroupService menuGroupService; @BeforeEach void setUp() { @@ -70,8 +70,7 @@ void findAll() { //then assertAll( () -> assertThat(menuGroups).hasSize(2), - () -> assertThat(menuGroups).extracting("name") - .contains(세트메뉴.getName(), 추천메뉴.getName()) + () -> assertThat(menuGroups).containsExactlyInAnyOrder(세트메뉴, 추천메뉴) ); } diff --git a/src/test/java/kitchenpos/application/OrderTableServiceTest.java b/src/test/java/kitchenpos/application/OrderTableServiceTest.java index 98fcdb4e4..be4fcef1d 100644 --- a/src/test/java/kitchenpos/application/OrderTableServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderTableServiceTest.java @@ -183,7 +183,7 @@ void findAll() { //then assertAll( () -> assertThat(orderTables).hasSize(2), - () -> assertThat(orderTables).contains(일번_테이블, 삼번_테이블) + () -> assertThat(orderTables).containsExactlyInAnyOrder(일번_테이블, 삼번_테이블) ); } From 8e30648415e4802bfd4b50803dac2f8b76c77729 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 08:23:36 +0900 Subject: [PATCH 24/40] test: id null check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit repository의 save는 수정 기능도 포함하고 있다. ID가 없을 경우에만 부여한다. --- .../kitchenpos/application/InMemoryMenuGroupRepository.java | 4 ++++ .../java/kitchenpos/application/InMemoryMenuRepository.java | 4 +++- .../java/kitchenpos/application/InMemoryOrderRepository.java | 5 ++++- .../kitchenpos/application/InMemoryOrderTableRepository.java | 5 ++++- .../kitchenpos/application/InMemoryProductRepository.java | 5 ++++- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java b/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java index 881841e71..ca872adb9 100644 --- a/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java +++ b/src/test/java/kitchenpos/application/InMemoryMenuGroupRepository.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.UUID; import kitchenpos.domain.MenuGroup; @@ -15,6 +16,9 @@ public class InMemoryMenuGroupRepository implements MenuGroupRepository { @Override public MenuGroup save(MenuGroup menuGroup) { + if (Objects.isNull(menuGroup.getId())) { + menuGroup.setId(UUID.randomUUID()); + } menuGroups.put(menuGroup.getId(), menuGroup); return menuGroup; } diff --git a/src/test/java/kitchenpos/application/InMemoryMenuRepository.java b/src/test/java/kitchenpos/application/InMemoryMenuRepository.java index 8b8521b9d..72afa42e8 100644 --- a/src/test/java/kitchenpos/application/InMemoryMenuRepository.java +++ b/src/test/java/kitchenpos/application/InMemoryMenuRepository.java @@ -40,7 +40,9 @@ public Optional findById(UUID menuId) { @Override public Menu save(Menu menu) { - menu.setId(UUID.randomUUID()); + if (Objects.isNull(menu.getId())) { + menu.setId(UUID.randomUUID()); + } menus.put(menu.getId(), menu); return menu; } diff --git a/src/test/java/kitchenpos/application/InMemoryOrderRepository.java b/src/test/java/kitchenpos/application/InMemoryOrderRepository.java index 0692558e7..da0af820f 100644 --- a/src/test/java/kitchenpos/application/InMemoryOrderRepository.java +++ b/src/test/java/kitchenpos/application/InMemoryOrderRepository.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.UUID; import kitchenpos.domain.Order; @@ -29,7 +30,9 @@ public boolean existsByOrderTableAndStatusNot(OrderTable orderTable, OrderStatus @Override public Order save(Order order) { - order.setId(UUID.randomUUID()); + if (Objects.isNull(order.getId())) { + order.setId(UUID.randomUUID()); + } orders.put(order.getId(), order); return order; } diff --git a/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java b/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java index 62baaa6dc..937446312 100644 --- a/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java +++ b/src/test/java/kitchenpos/application/InMemoryOrderTableRepository.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.UUID; import kitchenpos.domain.OrderTable; @@ -20,7 +21,9 @@ public Optional findById(UUID orderTableId) { @Override public OrderTable save(OrderTable orderTable) { - orderTable.setId(UUID.randomUUID()); + if (Objects.isNull(orderTable.getId())) { + orderTable.setId(UUID.randomUUID()); + } orderTables.put(orderTable.getId(), orderTable); return orderTable; } diff --git a/src/test/java/kitchenpos/application/InMemoryProductRepository.java b/src/test/java/kitchenpos/application/InMemoryProductRepository.java index eedb2558c..226b7047c 100644 --- a/src/test/java/kitchenpos/application/InMemoryProductRepository.java +++ b/src/test/java/kitchenpos/application/InMemoryProductRepository.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @@ -28,7 +29,9 @@ public Optional findById(UUID productId) { @Override public Product save(Product product) { - product.setId(UUID.randomUUID()); + if (Objects.isNull(product.getId())) { + product.setId(UUID.randomUUID()); + } products.put(product.getId(), product); return product; } From bca4cd18c82ea2d51c628cc569a1f9b63f453bef Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 08:48:39 +0900 Subject: [PATCH 25/40] =?UTF-8?q?chore:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/kitchenpos/application/MenuGroupFixture.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/kitchenpos/application/MenuGroupFixture.java b/src/test/java/kitchenpos/application/MenuGroupFixture.java index b71fc5de1..3a7afb9b4 100644 --- a/src/test/java/kitchenpos/application/MenuGroupFixture.java +++ b/src/test/java/kitchenpos/application/MenuGroupFixture.java @@ -1,7 +1,5 @@ package kitchenpos.application; -import java.util.Arrays; -import java.util.List; import java.util.UUID; import kitchenpos.domain.MenuGroup; @@ -9,7 +7,6 @@ public class MenuGroupFixture { public static final MenuGroup 세트메뉴 = new MenuGroup(); public static final MenuGroup 추천메뉴 = new MenuGroup(); - public static final List 메뉴판 = Arrays.asList(세트메뉴, 추천메뉴); static { initialize(세트메뉴, "세트메뉴"); From decba09f501381854f541e9507283c0adeed7547 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 08:54:38 +0900 Subject: [PATCH 26/40] =?UTF-8?q?refactor:=20enum=20=EB=B9=84=EA=B5=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit enum은 equals로 비교할 필요 없다. --- .../java/kitchenpos/application/InMemoryOrderRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/kitchenpos/application/InMemoryOrderRepository.java b/src/test/java/kitchenpos/application/InMemoryOrderRepository.java index da0af820f..1f40c7ac9 100644 --- a/src/test/java/kitchenpos/application/InMemoryOrderRepository.java +++ b/src/test/java/kitchenpos/application/InMemoryOrderRepository.java @@ -25,7 +25,7 @@ public Optional findById(UUID orderId) { public boolean existsByOrderTableAndStatusNot(OrderTable orderTable, OrderStatus status) { return orders.values().stream() .anyMatch( - order -> order.getOrderTableId().equals(orderTable.getId()) && !order.getStatus().equals(status)); + order -> order.getOrderTableId().equals(orderTable.getId()) && order.getStatus() != status); } @Override From d86cfce8050232d06d930e04a96239acbfc3a008 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 21:47:19 +0900 Subject: [PATCH 27/40] =?UTF-8?q?test:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트의 의도를 명확하게 표현할 수 있는 변수명으로 변경 --- src/test/java/kitchenpos/application/MenuServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index fe2b06283..d301f8669 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -64,10 +64,10 @@ void createPriceUnderZeroException(BigDecimal price) { @Test void createMenuGroupNotExistException() { //given - Menu 메뉴_그룹_없는_메뉴 = 메뉴_생성(11_000); + Menu 메뉴_그룹에_속하지_않은_메뉴 = 메뉴_생성(11_000); //when - ThrowingCallable actual = () -> menuService.create(메뉴_그룹_없는_메뉴); + ThrowingCallable actual = () -> menuService.create(메뉴_그룹에_속하지_않은_메뉴); //then assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); From 945a61e292b6d1d8610eadb18304dcdf77a24588 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 21:50:07 +0900 Subject: [PATCH 28/40] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=AA=85=20=EB=B0=8F=20=EB=B3=80=EC=88=98=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트의 의도를 명확하게 표현할 수 있는 테스트 이름과 변수명으로 변경 --- .../java/kitchenpos/application/MenuServiceTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index d301f8669..4465ad41d 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -108,7 +108,7 @@ void createMenuProductsMismatchException() { assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("메뉴는 수량이 부족한 상품을 포함할 수 없다.") + @DisplayName("메뉴는 수량이 부족한 메뉴상품을 포함할 수 없다.") @Test void createMenuProductsLackQuantityException() { //given @@ -116,12 +116,12 @@ void createMenuProductsLackQuantityException() { productRepository.save(맛초킹); productRepository.save(콜라); - Menu 상품_수량_오류_메뉴 = 메뉴_생성(11_000); - 상품_수량_오류_메뉴.setMenuGroupId(세트_메뉴.getId()); - 상품_수량_오류_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_수량_오류)); + Menu 메뉴상품_수량_오류_메뉴 = 메뉴_생성(11_000); + 메뉴상품_수량_오류_메뉴.setMenuGroupId(세트_메뉴.getId()); + 메뉴상품_수량_오류_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_수량_오류)); //when - ThrowingCallable actual = () -> menuService.create(상품_수량_오류_메뉴); + ThrowingCallable actual = () -> menuService.create(메뉴상품_수량_오류_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); From e570be7021d8ded633db8e31d5844cbc5c026fd2 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 30 Mar 2022 21:55:28 +0900 Subject: [PATCH 29/40] =?UTF-8?q?test:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테이블 -> 식탁 일치 하지 않은 용어로 혼란을 줄 수 있는 요소 제거. --- .../kitchenpos/application/OrderFixture.java | 6 +-- .../application/OrderTableFixture.java | 12 +++--- .../application/OrderTableServiceTest.java | 40 +++++++++---------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/test/java/kitchenpos/application/OrderFixture.java b/src/test/java/kitchenpos/application/OrderFixture.java index 688163547..56ae0bfa5 100644 --- a/src/test/java/kitchenpos/application/OrderFixture.java +++ b/src/test/java/kitchenpos/application/OrderFixture.java @@ -2,7 +2,7 @@ import static kitchenpos.application.MenuFixture.맛초킹_세트; import static kitchenpos.application.MenuFixture.뿌링클_세트; -import static kitchenpos.application.OrderTableFixture.일번_테이블; +import static kitchenpos.application.OrderTableFixture.일번_식탁; import java.util.Arrays; import java.util.Collections; @@ -21,8 +21,8 @@ public class OrderFixture { 매장_주문.setId(UUID.randomUUID()); 매장_주문.setType(OrderType.EAT_IN); 매장_주문.setOrderLineItems(Collections.singletonList(주문_항목_뿌링클_세트())); - 매장_주문.setOrderTable(일번_테이블); - 매장_주문.setOrderTableId(일번_테이블.getId()); + 매장_주문.setOrderTable(일번_식탁); + 매장_주문.setOrderTableId(일번_식탁.getId()); 포장_주문.setId(UUID.randomUUID()); 포장_주문.setType(OrderType.TAKEOUT); diff --git a/src/test/java/kitchenpos/application/OrderTableFixture.java b/src/test/java/kitchenpos/application/OrderTableFixture.java index 73a82b293..30ef8ba0c 100644 --- a/src/test/java/kitchenpos/application/OrderTableFixture.java +++ b/src/test/java/kitchenpos/application/OrderTableFixture.java @@ -5,14 +5,14 @@ public class OrderTableFixture { - public static final OrderTable 일번_테이블 = new OrderTable(); - public static final OrderTable 삼번_테이블 = new OrderTable(); - public static final OrderTable 착석_테이블 = new OrderTable(); + public static final OrderTable 일번_식탁 = new OrderTable(); + public static final OrderTable 삼번_식탁 = new OrderTable(); + public static final OrderTable 착석_식탁 = new OrderTable(); static { - initialize(일번_테이블, "1번"); - initialize(삼번_테이블, "3번"); - initialize(착석_테이블, "5번", false); + initialize(일번_식탁, "1번"); + initialize(삼번_식탁, "3번"); + initialize(착석_식탁, "5번", false); } private static void initialize(OrderTable orderTable, String name) { diff --git a/src/test/java/kitchenpos/application/OrderTableServiceTest.java b/src/test/java/kitchenpos/application/OrderTableServiceTest.java index be4fcef1d..70baddb26 100644 --- a/src/test/java/kitchenpos/application/OrderTableServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderTableServiceTest.java @@ -1,8 +1,8 @@ package kitchenpos.application; -import static kitchenpos.application.OrderTableFixture.삼번_테이블; -import static kitchenpos.application.OrderTableFixture.일번_테이블; +import static kitchenpos.application.OrderTableFixture.삼번_식탁; +import static kitchenpos.application.OrderTableFixture.일번_식탁; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; @@ -53,14 +53,14 @@ void createException(String orderTableName) { @Test void create() { //given - OrderTable 신규_테이블 = 식탁_생성("3번"); + OrderTable 신규_식탁 = 식탁_생성("3번"); //when - OrderTable orderTable = orderTableService.create(신규_테이블); + OrderTable orderTable = orderTableService.create(신규_식탁); //then assertAll( - () -> assertThat(orderTable.getName()).isEqualTo(신규_테이블.getName()), + () -> assertThat(orderTable.getName()).isEqualTo(신규_식탁.getName()), () -> assertThat(orderTable.getNumberOfGuests()).isZero(), () -> assertThat(orderTable.isEmpty()).isTrue() ); @@ -88,7 +88,7 @@ void changeNumberOfGuestsException() { OrderTable 손님_수_변경 = 식탁_생성(-1); //when - ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_테이블.getId(), 손님_수_변경); + ThrowingCallable actual = () -> orderTableService.changeNumberOfGuests(일번_식탁.getId(), 손님_수_변경); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); @@ -114,12 +114,12 @@ void tableIsEmptyThenChangeNumberOfGuestsException() { @Test void changeNumberOfGuests() { //given - OrderTable 삼번_테이블 = 식탁_생성("3번 테이블", 3, false); - orderTableRepository.save(삼번_테이블); + OrderTable 삼번_식탁 = 식탁_생성("3번 식탁", 3, false); + orderTableRepository.save(삼번_식탁); OrderTable 손님_수_변경 = 식탁_생성(4); //when - OrderTable orderTable = orderTableService.changeNumberOfGuests(삼번_테이블.getId(), 손님_수_변경); + OrderTable orderTable = orderTableService.changeNumberOfGuests(삼번_식탁.getId(), 손님_수_변경); //then assertAll( @@ -133,16 +133,16 @@ void changeNumberOfGuests() { @EnumSource(value = OrderStatus.class, names = {"COMPLETED"}, mode = Mode.EXCLUDE) void clearException(OrderStatus orderStatus) { //given - OrderTable 삼번_테이블 = 식탁_생성("3번 테이블", 3, false); - orderTableRepository.save(삼번_테이블); + OrderTable 삼번_식탁 = 식탁_생성("3번 식탁", 3, false); + orderTableRepository.save(삼번_식탁); Order 매장_주문 = new Order(); - 매장_주문.setOrderTableId(삼번_테이블.getId()); + 매장_주문.setOrderTableId(삼번_식탁.getId()); 매장_주문.setStatus(orderStatus); orderRepository.save(매장_주문); //when - ThrowingCallable actual = () -> orderTableService.clear(삼번_테이블.getId()); + ThrowingCallable actual = () -> orderTableService.clear(삼번_식탁.getId()); //then assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); @@ -152,16 +152,16 @@ void clearException(OrderStatus orderStatus) { @Test void clear() { //given - OrderTable 삼번_테이블 = 식탁_생성("3번 테이블", 3, false); - orderTableRepository.save(삼번_테이블); + OrderTable 삼번_식탁 = 식탁_생성("3번 식탁", 3, false); + orderTableRepository.save(삼번_식탁); Order 매장_주문 = new Order(); - 매장_주문.setOrderTableId(삼번_테이블.getId()); + 매장_주문.setOrderTableId(삼번_식탁.getId()); 매장_주문.setStatus(OrderStatus.COMPLETED); orderRepository.save(매장_주문); //when - OrderTable cleanTable = orderTableService.clear(삼번_테이블.getId()); + OrderTable cleanTable = orderTableService.clear(삼번_식탁.getId()); //then assertAll( @@ -174,8 +174,8 @@ void clear() { @Test void findAll() { //given - orderTableRepository.save(일번_테이블); - orderTableRepository.save(삼번_테이블); + orderTableRepository.save(일번_식탁); + orderTableRepository.save(삼번_식탁); //when List orderTables = orderTableService.findAll(); @@ -183,7 +183,7 @@ void findAll() { //then assertAll( () -> assertThat(orderTables).hasSize(2), - () -> assertThat(orderTables).containsExactlyInAnyOrder(일번_테이블, 삼번_테이블) + () -> assertThat(orderTables).containsExactlyInAnyOrder(일번_식탁, 삼번_식탁) ); } From 1998e765bc1b140046a4f93295347ae607121ab8 Mon Sep 17 00:00:00 2001 From: yongju Date: Mon, 4 Apr 2022 08:08:59 +0900 Subject: [PATCH 30/40] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트는 하나의 논리적 개념만 검증한다. 레거시 코드에서 여러 책임을 수행하고 있더라도 테스트 코드는 하나의 논리적 개념만 검증하도록 해야 한다. --- .../application/ProductServiceTest.java | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/test/java/kitchenpos/application/ProductServiceTest.java b/src/test/java/kitchenpos/application/ProductServiceTest.java index fd79ba8a1..d659b36b7 100644 --- a/src/test/java/kitchenpos/application/ProductServiceTest.java +++ b/src/test/java/kitchenpos/application/ProductServiceTest.java @@ -1,12 +1,10 @@ package kitchenpos.application; -import static kitchenpos.application.MenuProductFixture.뿌링클_1개; import static kitchenpos.application.MenuProductFixture.콜라_1개; import static kitchenpos.application.ProductFixture.뿌링클; import static kitchenpos.application.ProductFixture.콜라; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; import java.math.BigDecimal; import java.util.Arrays; @@ -72,13 +70,32 @@ void createNameException(String name) { assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); } - @DisplayName("가격을 변경할 수 있다. 가격이 해당 상품을 포함하는 메뉴의 가격보다 크면 메뉴를 진열하지 않는다.") + @DisplayName("가격을 변경할 수 있다") + @ParameterizedTest(name = "변경할 가격: [{0}]") + @CsvSource(value = { + "8000", + "15000" + }) + void changePrice(long price) { + //given + Product 신규_상품 = productRepository.save(상품_생성(12_000)); + + Product 변경할_금액 = 상품_생성(price); + + //when + Product product = productService.changePrice(신규_상품.getId(), 변경할_금액); + + //then + assertThat(product.getPrice()).isEqualTo(BigDecimal.valueOf(price)); + } + + @DisplayName("상품의 가격이 해당 상품을 포함하는 메뉴의 가격보다 크면 메뉴를 진열하지 않는다.") @ParameterizedTest(name = "변경할 가격: [{0}], 진열 여부: [{1}]") @CsvSource(value = { "8000, false", "15000, true" }) - void changePrice(long price, boolean expectedDisplayed) { + void changePriceThenMenuDisplayed(long price, boolean expectedDisplayed) { //given Product 신규_상품 = productRepository.save(상품_생성(12_000)); @@ -87,7 +104,7 @@ void changePrice(long price, boolean expectedDisplayed) { menuProduct.setProductId(신규_상품.getId()); menuProduct.setQuantity(1); - Menu menu = new Menu(); + Menu menu = new MenuBuilder().build(); menu.setDisplayed(true); menu.setMenuProducts(Arrays.asList(menuProduct, 콜라_1개)); menu.setPrice(BigDecimal.valueOf(11_000L)); @@ -96,13 +113,10 @@ void changePrice(long price, boolean expectedDisplayed) { Product 변경할_금액 = 상품_생성(price); //when - Product product = productService.changePrice(신규_상품.getId(), 변경할_금액); + productService.changePrice(신규_상품.getId(), 변경할_금액); //then - assertAll( - () -> assertThat(product.getPrice()).isEqualTo(BigDecimal.valueOf(price)), - () -> assertThat(menu.isDisplayed()).isEqualTo(expectedDisplayed) - ); + assertThat(menu.isDisplayed()).isEqualTo(expectedDisplayed); } @DisplayName("0원 미만의 가격으로 변경할 수 없다.") From cfdbf9fbe09b18cc22d074b347872e211e600afa Mon Sep 17 00:00:00 2001 From: yongju Date: Mon, 4 Apr 2022 08:17:08 +0900 Subject: [PATCH 31/40] =?UTF-8?q?test:=20=EC=8B=9C=EA=B0=84=EC=A0=81=20?= =?UTF-8?q?=EA=B2=B0=ED=95=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 레거시 코드의 순서대로 테스트를 하고 있다. 레거시 코드가 변경되면 테스트의 성공여부를 확신할 수 없다. 즉 안전한 테스트 코드라고 할 수 없다. 레거시 코드가 변경되어도 테스트는 온전한 기능을 해야한다. 순서에 의존하지 않아도 되는 코드에는 선행조건을 만들지 말고 독립적인 실행을 보장해야 한다. --- .../kitchenpos/application/MenuBuilder.java | 70 +++++++++++++++ .../application/MenuServiceTest.java | 88 ++++++++++++------- 2 files changed, 127 insertions(+), 31 deletions(-) create mode 100644 src/test/java/kitchenpos/application/MenuBuilder.java diff --git a/src/test/java/kitchenpos/application/MenuBuilder.java b/src/test/java/kitchenpos/application/MenuBuilder.java new file mode 100644 index 000000000..0737ebd32 --- /dev/null +++ b/src/test/java/kitchenpos/application/MenuBuilder.java @@ -0,0 +1,70 @@ +package kitchenpos.application; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuGroup; +import kitchenpos.domain.MenuProduct; + +public class MenuBuilder { + + private String name; + private BigDecimal price; + private MenuGroup menuGroup; + private boolean displayed; + private List menuProducts; + private UUID menuGroupId; + + public MenuBuilder withName(String name) { + this.name = name; + return this; + } + + public MenuBuilder withPrice(long price) { + this.price = BigDecimal.valueOf(price); + return this; + } + + public MenuBuilder withPrice(BigDecimal price) { + this.price = price; + return this; + } + + public MenuBuilder withMenuGroup(MenuGroup menuGroup) { + this.menuGroup = menuGroup; + return this; + } + + public MenuBuilder withDisplayed(boolean displayed) { + this.displayed = displayed; + return this; + } + + public MenuBuilder withMenuProducts(List menuProducts) { + this.menuProducts = menuProducts; + return this; + } + + public MenuBuilder withMenuProducts(MenuProduct... menuProducts) { + this.menuProducts = Arrays.asList(menuProducts); + return this; + } + + public MenuBuilder withMenuGroupId(UUID menuGroupId) { + this.menuGroupId = menuGroupId; + return this; + } + + public Menu build() { + Menu menu = new Menu(); + menu.setName(name); + menu.setPrice(price); + menu.setMenuGroup(menuGroup); + menu.setDisplayed(displayed); + menu.setMenuProducts(menuProducts); + menu.setMenuGroupId(menuGroupId); + return menu; + } +} diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index 4465ad41d..d8c4f49ac 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; +import java.util.UUID; import kitchenpos.domain.Menu; import kitchenpos.domain.MenuGroup; import kitchenpos.domain.MenuGroupRepository; @@ -51,7 +52,9 @@ void setUp() { @NullSource void createPriceUnderZeroException(BigDecimal price) { //given - Menu 잘못된_가격의_메뉴 = 메뉴_생성(price); + Menu 잘못된_가격의_메뉴 = 메뉴생성() + .withPrice(price) + .build(); //when ThrowingCallable actual = () -> menuService.create(잘못된_가격의_메뉴); @@ -64,7 +67,9 @@ void createPriceUnderZeroException(BigDecimal price) { @Test void createMenuGroupNotExistException() { //given - Menu 메뉴_그룹에_속하지_않은_메뉴 = 메뉴_생성(11_000); + Menu 메뉴_그룹에_속하지_않은_메뉴 = 메뉴생성() + .withMenuGroup(null) + .build(); //when ThrowingCallable actual = () -> menuService.create(메뉴_그룹에_속하지_않은_메뉴); @@ -79,8 +84,10 @@ void createMenuProductsNotExistException() { //given MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - Menu 상품_없는_메뉴 = 메뉴_생성(11_000); - 상품_없는_메뉴.setMenuGroupId(세트_메뉴.getId()); + Menu 상품_없는_메뉴 = 메뉴생성() + .withMenuGroup(세트_메뉴) + .withMenuGroupId(세트_메뉴.getId()) + .build(); //when ThrowingCallable actual = () -> menuService.create(상품_없는_메뉴); @@ -97,12 +104,14 @@ void createMenuProductsMismatchException() { productRepository.save(맛초킹); productRepository.save(콜라); - Menu 상품_없는_메뉴 = 메뉴_생성(11_000); - 상품_없는_메뉴.setMenuGroupId(세트_메뉴.getId()); - 상품_없는_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 맛초킹_1개, 콜라_1개)); + Menu 중복된_상품을_포함하는_메뉴 = 메뉴생성() + .withMenuGroup(세트_메뉴) + .withMenuGroupId(세트_메뉴.getId()) + .withMenuProducts(맛초킹_1개, 맛초킹_1개, 콜라_1개) + .build(); //when - ThrowingCallable actual = () -> menuService.create(상품_없는_메뉴); + ThrowingCallable actual = () -> menuService.create(중복된_상품을_포함하는_메뉴); //then assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); @@ -116,9 +125,11 @@ void createMenuProductsLackQuantityException() { productRepository.save(맛초킹); productRepository.save(콜라); - Menu 메뉴상품_수량_오류_메뉴 = 메뉴_생성(11_000); - 메뉴상품_수량_오류_메뉴.setMenuGroupId(세트_메뉴.getId()); - 메뉴상품_수량_오류_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_수량_오류)); + Menu 메뉴상품_수량_오류_메뉴 = 메뉴생성() + .withMenuGroup(세트_메뉴) + .withMenuGroupId(세트_메뉴.getId()) + .withMenuProducts(맛초킹_1개, 콜라_수량_오류) + .build(); //when ThrowingCallable actual = () -> menuService.create(메뉴상품_수량_오류_메뉴); @@ -135,9 +146,12 @@ void createPriceException() { productRepository.save(맛초킹); productRepository.save(콜라); - Menu 비싼_메뉴 = 메뉴_생성(15_000); - 비싼_메뉴.setMenuGroupId(세트_메뉴.getId()); - 비싼_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)); + Menu 비싼_메뉴 = 메뉴생성() + .withPrice(15_000L) + .withMenuGroup(세트_메뉴) + .withMenuGroupId(세트_메뉴.getId()) + .withMenuProducts(맛초킹_1개, 콜라_1개) + .build(); //when ThrowingCallable actual = () -> menuService.create(비싼_메뉴); @@ -154,10 +168,11 @@ void createNameException() { productRepository.save(맛초킹); productRepository.save(콜라); - Menu 비속어_메뉴 = 메뉴_생성(11_000); - 비속어_메뉴.setMenuGroupId(세트_메뉴.getId()); - 비속어_메뉴.setMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)); - 비속어_메뉴.setName("비속어"); + Menu 비속어_메뉴 = 메뉴생성() + .withName("비속어") + .withMenuGroupId(세트_메뉴.getId()) + .withMenuProducts(맛초킹_1개, 콜라_1개) + .build(); //when ThrowingCallable actual = () -> menuService.create(비속어_메뉴); @@ -190,7 +205,7 @@ void create() { @NullSource void changePriceException(BigDecimal price) { //given - Menu 포장_전용_메뉴 = menuRepository.save(메뉴_생성(20_000)); + Menu 포장_전용_메뉴 = menuRepository.save(메뉴생성().build()); Menu 가격_변경 = 메뉴_생성(price); @@ -234,7 +249,7 @@ void changePrice() { @Test void displayNotExistException() { //given - Menu 없는_메뉴 = new Menu(); + Menu 없는_메뉴 = new MenuBuilder().build(); //when ThrowingCallable actual = () -> menuService.display(없는_메뉴.getId()); @@ -273,7 +288,7 @@ void display() { @Test void hideException() { //given - Menu 없는_메뉴 = new Menu(); + Menu 없는_메뉴 = new MenuBuilder().build(); //when ThrowingCallable actual = () -> menuService.hide(없는_메뉴.getId()); @@ -299,8 +314,8 @@ void hide() { @Test void findALl() { //given - menuRepository.save(메뉴_생성(10_000)); - menuRepository.save(메뉴_생성(20_000)); + menuRepository.save(메뉴생성().build()); + menuRepository.save(메뉴생성().build()); //when List actual = menuService.findAll(); @@ -317,11 +332,13 @@ void findALl() { MenuProduct 맛초킹1개 = 메뉴_상품_생성(맛초킹); MenuProduct 콜라1개 = 메뉴_상품_생성(콜라); - Menu 맛초킹_세트 = 메뉴_생성(price); - 맛초킹_세트.setMenuGroupId(세트_메뉴.getId()); - 맛초킹_세트.setMenuProducts(Arrays.asList(맛초킹1개, 콜라1개)); - 맛초킹_세트.setName("맛초킹 세트"); - + Menu 맛초킹_세트 = 메뉴생성() + .withMenuGroupId(세트_메뉴.getId()) + .withMenuGroup(세트메뉴) + .withMenuProducts(Arrays.asList(맛초킹1개, 콜라1개)) + .withName("맛초킹 세트") + .withPrice(price) + .build(); return menuRepository.save(맛초킹_세트); } @@ -338,9 +355,18 @@ void findALl() { } private Menu 메뉴_생성(BigDecimal price) { - Menu menu = new Menu(); - menu.setPrice(price); - return menu; + return new MenuBuilder() + .withPrice(price) + .build(); } + private MenuBuilder 메뉴생성() { + return new MenuBuilder() + .withMenuGroup(new MenuGroup()) + .withMenuGroupId(UUID.randomUUID()) + .withName("맛초킹 세트") + .withDisplayed(true) + .withMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개)) + .withPrice(BigDecimal.valueOf(11_000L)); + } } From 17c7f41bfb149993cba0a8dc4715bc2dbc3962cd Mon Sep 17 00:00:00 2001 From: yongju Date: Tue, 5 Apr 2022 07:38:16 +0900 Subject: [PATCH 32/40] =?UTF-8?q?test:=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/kitchenpos/application/MenuServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index d8c4f49ac..6a70c67b5 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -312,7 +312,7 @@ void hide() { @DisplayName("모든 메뉴 조회") @Test - void findALl() { + void findAll() { //given menuRepository.save(메뉴생성().build()); menuRepository.save(메뉴생성().build()); From 26bd4cabb593ce42569f9fef021512054dd77776 Mon Sep 17 00:00:00 2001 From: yongju Date: Tue, 5 Apr 2022 07:39:17 +0900 Subject: [PATCH 33/40] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EA=B3=B5=EB=B0=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kitchenpos/domain/MenuGroupRepository.java | 1 - src/main/java/kitchenpos/domain/MenuRepository.java | 1 - src/main/java/kitchenpos/domain/OrderRepository.java | 1 - src/main/java/kitchenpos/domain/OrderTableRepository.java | 1 - src/main/java/kitchenpos/domain/ProductRepository.java | 1 - 5 files changed, 5 deletions(-) diff --git a/src/main/java/kitchenpos/domain/MenuGroupRepository.java b/src/main/java/kitchenpos/domain/MenuGroupRepository.java index 8691dd837..2b0cbaef3 100644 --- a/src/main/java/kitchenpos/domain/MenuGroupRepository.java +++ b/src/main/java/kitchenpos/domain/MenuGroupRepository.java @@ -12,4 +12,3 @@ public interface MenuGroupRepository { Optional findById(UUID menuGroupId); } - diff --git a/src/main/java/kitchenpos/domain/MenuRepository.java b/src/main/java/kitchenpos/domain/MenuRepository.java index 056405e12..fc6df7108 100644 --- a/src/main/java/kitchenpos/domain/MenuRepository.java +++ b/src/main/java/kitchenpos/domain/MenuRepository.java @@ -19,4 +19,3 @@ public interface MenuRepository { List findAll(); } - diff --git a/src/main/java/kitchenpos/domain/OrderRepository.java b/src/main/java/kitchenpos/domain/OrderRepository.java index 57fd7eb14..31a046734 100644 --- a/src/main/java/kitchenpos/domain/OrderRepository.java +++ b/src/main/java/kitchenpos/domain/OrderRepository.java @@ -13,4 +13,3 @@ public interface OrderRepository { List findAll(); } - diff --git a/src/main/java/kitchenpos/domain/OrderTableRepository.java b/src/main/java/kitchenpos/domain/OrderTableRepository.java index 5a9679432..2ca9da812 100644 --- a/src/main/java/kitchenpos/domain/OrderTableRepository.java +++ b/src/main/java/kitchenpos/domain/OrderTableRepository.java @@ -12,4 +12,3 @@ public interface OrderTableRepository { List findAll(); } - diff --git a/src/main/java/kitchenpos/domain/ProductRepository.java b/src/main/java/kitchenpos/domain/ProductRepository.java index 7e72522f4..db20db39e 100644 --- a/src/main/java/kitchenpos/domain/ProductRepository.java +++ b/src/main/java/kitchenpos/domain/ProductRepository.java @@ -13,4 +13,3 @@ public interface ProductRepository { List findAll(); } - From 72e13aef0c4df95d1e8b7b2e54b03423ccd1ab7a Mon Sep 17 00:00:00 2001 From: yongju Date: Tue, 5 Apr 2022 07:44:49 +0900 Subject: [PATCH 34/40] =?UTF-8?q?refactor:=20MenuRepository=EC=97=90?= =?UTF-8?q?=EC=84=9C=20data-jpa=20=EC=9D=98=EC=A1=B4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kitchenpos/domain/JpaMenuRepository.java | 7 +++++++ src/main/java/kitchenpos/domain/MenuRepository.java | 5 +---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/kitchenpos/domain/JpaMenuRepository.java b/src/main/java/kitchenpos/domain/JpaMenuRepository.java index 1f3f51dbc..7a0f0c149 100644 --- a/src/main/java/kitchenpos/domain/JpaMenuRepository.java +++ b/src/main/java/kitchenpos/domain/JpaMenuRepository.java @@ -1,8 +1,15 @@ package kitchenpos.domain; +import java.util.List; import java.util.UUID; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; interface JpaMenuRepository extends MenuRepository, JpaRepository { + @Override + @Query("select m from Menu m, MenuProduct mp where mp.product.id = :productId") + List findAllByProductId(@Param("productId") UUID productId); + } diff --git a/src/main/java/kitchenpos/domain/MenuRepository.java b/src/main/java/kitchenpos/domain/MenuRepository.java index fc6df7108..558aafd81 100644 --- a/src/main/java/kitchenpos/domain/MenuRepository.java +++ b/src/main/java/kitchenpos/domain/MenuRepository.java @@ -3,14 +3,11 @@ import java.util.List; import java.util.Optional; import java.util.UUID; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface MenuRepository { List findAllByIdIn(List ids); - @Query("select m from Menu m, MenuProduct mp where mp.product.id = :productId") - List findAllByProductId(@Param("productId") UUID productId); + List findAllByProductId(UUID productId); Optional findById(UUID menuId); From a42c02296da3e7795b43fb1a357e5b289e9972bc Mon Sep 17 00:00:00 2001 From: yongju Date: Mon, 11 Apr 2022 08:00:08 +0900 Subject: [PATCH 35/40] =?UTF-8?q?test(feedback):=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EA=B2=80=EC=A6=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit containsExactly 는 hasSize를 포함한다. --- .../kitchenpos/application/DefaultMenuGroupServiceTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java b/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java index 4944a10d4..f200ebade 100644 --- a/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java +++ b/src/test/java/kitchenpos/application/DefaultMenuGroupServiceTest.java @@ -68,10 +68,7 @@ void findAll() { List menuGroups = menuGroupService.findAll(); //then - assertAll( - () -> assertThat(menuGroups).hasSize(2), - () -> assertThat(menuGroups).containsExactlyInAnyOrder(세트메뉴, 추천메뉴) - ); + assertThat(menuGroups).containsExactlyInAnyOrder(세트메뉴, 추천메뉴); } private MenuGroup 메뉴_그룹_생성(String name) { From bec4eb06ac1d3903de0a7e08def7e783a651252a Mon Sep 17 00:00:00 2001 From: yongju Date: Mon, 11 Apr 2022 08:02:52 +0900 Subject: [PATCH 36/40] =?UTF-8?q?style(feedback):=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B0=80=EB=8F=85=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preferences - Tools - Actions to Save Reformat code, Optimize imports 활성화 --- src/main/java/kitchenpos/domain/OrderRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/kitchenpos/domain/OrderRepository.java b/src/main/java/kitchenpos/domain/OrderRepository.java index 31a046734..37012e654 100644 --- a/src/main/java/kitchenpos/domain/OrderRepository.java +++ b/src/main/java/kitchenpos/domain/OrderRepository.java @@ -7,6 +7,7 @@ public interface OrderRepository { Optional findById(UUID orderId); + boolean existsByOrderTableAndStatusNot(OrderTable orderTable, OrderStatus status); Order save(Order order); From a3af1e729fff6604c3d34e2e6deacb0377461466 Mon Sep 17 00:00:00 2001 From: yongju Date: Mon, 11 Apr 2022 08:04:33 +0900 Subject: [PATCH 37/40] =?UTF-8?q?refactor:=20=EC=BB=A4=EC=8A=A4=ED=85=80?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kitchenpos/application/MenuService.java | 21 ++++++++++++------- .../domain/exception/MenuMarginException.java | 11 ++++++++++ .../domain/exception/MenuPriceException.java | 9 ++++++++ .../exception/MenuProductException.java | 8 +++++++ .../MenuProductNotExistException.java | 8 +++++++ .../MenuProductQuantityException.java | 8 +++++++ .../application/MenuServiceTest.java | 21 ++++++++++++------- 7 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 src/main/java/kitchenpos/domain/exception/MenuMarginException.java create mode 100644 src/main/java/kitchenpos/domain/exception/MenuPriceException.java create mode 100644 src/main/java/kitchenpos/domain/exception/MenuProductException.java create mode 100644 src/main/java/kitchenpos/domain/exception/MenuProductNotExistException.java create mode 100644 src/main/java/kitchenpos/domain/exception/MenuProductQuantityException.java diff --git a/src/main/java/kitchenpos/application/MenuService.java b/src/main/java/kitchenpos/application/MenuService.java index 0fb63ff8f..e3445798f 100644 --- a/src/main/java/kitchenpos/application/MenuService.java +++ b/src/main/java/kitchenpos/application/MenuService.java @@ -14,6 +14,11 @@ import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; +import kitchenpos.domain.exception.MenuMarginException; +import kitchenpos.domain.exception.MenuPriceException; +import kitchenpos.domain.exception.MenuProductException; +import kitchenpos.domain.exception.MenuProductNotExistException; +import kitchenpos.domain.exception.MenuProductQuantityException; import kitchenpos.infra.ProfanityClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -41,13 +46,13 @@ public MenuService( public Menu create(final Menu request) { final BigDecimal price = request.getPrice(); if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) { - throw new IllegalArgumentException(); + throw new MenuPriceException(); } final MenuGroup menuGroup = menuGroupRepository.findById(request.getMenuGroupId()) .orElseThrow(NoSuchElementException::new); final List menuProductRequests = request.getMenuProducts(); if (Objects.isNull(menuProductRequests) || menuProductRequests.isEmpty()) { - throw new IllegalArgumentException(); + throw new MenuProductNotExistException(); } final List products = productRepository.findAllByIdIn( menuProductRequests.stream() @@ -55,14 +60,14 @@ public Menu create(final Menu request) { .collect(Collectors.toList()) ); if (products.size() != menuProductRequests.size()) { - throw new IllegalArgumentException(); + throw new MenuProductException(menuProductRequests.size(), products.size()); } final List menuProducts = new ArrayList<>(); BigDecimal sum = BigDecimal.ZERO; for (final MenuProduct menuProductRequest : menuProductRequests) { final long quantity = menuProductRequest.getQuantity(); if (quantity < 0) { - throw new IllegalArgumentException(); + throw new MenuProductQuantityException(quantity); } final Product product = productRepository.findById(menuProductRequest.getProductId()) .orElseThrow(NoSuchElementException::new); @@ -76,7 +81,7 @@ public Menu create(final Menu request) { menuProducts.add(menuProduct); } if (price.compareTo(sum) > 0) { - throw new IllegalArgumentException(); + throw new MenuMarginException(price, sum); } final String name = request.getName(); if (Objects.isNull(name) || profanityClient.containsProfanity(name)) { @@ -96,7 +101,7 @@ public Menu create(final Menu request) { public Menu changePrice(final UUID menuId, final Menu request) { final BigDecimal price = request.getPrice(); if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) { - throw new IllegalArgumentException(); + throw new MenuPriceException(); } final Menu menu = menuRepository.findById(menuId) .orElseThrow(NoSuchElementException::new); @@ -107,7 +112,7 @@ public Menu changePrice(final UUID menuId, final Menu request) { .multiply(BigDecimal.valueOf(menuProduct.getQuantity()))); } if (price.compareTo(sum) > 0) { - throw new IllegalArgumentException(); + throw new MenuMarginException(price, sum); } menu.setPrice(price); return menu; @@ -124,7 +129,7 @@ public Menu display(final UUID menuId) { .multiply(BigDecimal.valueOf(menuProduct.getQuantity()))); } if (menu.getPrice().compareTo(sum) > 0) { - throw new IllegalStateException(); + throw new MenuMarginException(menu.getPrice(), sum); } menu.setDisplayed(true); return menu; diff --git a/src/main/java/kitchenpos/domain/exception/MenuMarginException.java b/src/main/java/kitchenpos/domain/exception/MenuMarginException.java new file mode 100644 index 000000000..999f045df --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/MenuMarginException.java @@ -0,0 +1,11 @@ +package kitchenpos.domain.exception; + +import java.math.BigDecimal; + +public class MenuMarginException extends IllegalArgumentException { + + public MenuMarginException(BigDecimal price, BigDecimal sum) { + super("메뉴의 가격은 주문하는 상품들의 가격의 합보다 작아야 합니다. " + + "가격 : " + price.longValue() + ", 주문하는 상품들의 가격의 합 : " + sum.longValue()); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/MenuPriceException.java b/src/main/java/kitchenpos/domain/exception/MenuPriceException.java new file mode 100644 index 000000000..409217aad --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/MenuPriceException.java @@ -0,0 +1,9 @@ +package kitchenpos.domain.exception; + +public class MenuPriceException extends IllegalArgumentException { + + public MenuPriceException() { + super("메뉴의 가격은 0원 이상이어야 합니다."); + } + +} diff --git a/src/main/java/kitchenpos/domain/exception/MenuProductException.java b/src/main/java/kitchenpos/domain/exception/MenuProductException.java new file mode 100644 index 000000000..a235f54cd --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/MenuProductException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class MenuProductException extends IllegalArgumentException { + + public MenuProductException(int requestProductSize, int productSize) { + super("주문하는 메뉴 상품과 실제 메뉴 상품의 수가 일치하지 않습니다. 주문 : " + requestProductSize + ", 실제 : " + productSize); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/MenuProductNotExistException.java b/src/main/java/kitchenpos/domain/exception/MenuProductNotExistException.java new file mode 100644 index 000000000..024cd92dc --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/MenuProductNotExistException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class MenuProductNotExistException extends IllegalArgumentException { + + public MenuProductNotExistException() { + super("하나 이상의 메뉴 상품을 포함해야 합니다."); + } +} diff --git a/src/main/java/kitchenpos/domain/exception/MenuProductQuantityException.java b/src/main/java/kitchenpos/domain/exception/MenuProductQuantityException.java new file mode 100644 index 000000000..74234ba32 --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/MenuProductQuantityException.java @@ -0,0 +1,8 @@ +package kitchenpos.domain.exception; + +public class MenuProductQuantityException extends IllegalArgumentException { + + public MenuProductQuantityException(long quantity) { + super("주문하는 상품의 수량은 0 이상이어야 합니다. 주문하려는 상품의 수량 : " + quantity); + } +} diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index 6a70c67b5..5b3181662 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -22,6 +22,11 @@ import kitchenpos.domain.MenuRepository; import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; +import kitchenpos.domain.exception.MenuMarginException; +import kitchenpos.domain.exception.MenuPriceException; +import kitchenpos.domain.exception.MenuProductException; +import kitchenpos.domain.exception.MenuProductNotExistException; +import kitchenpos.domain.exception.MenuProductQuantityException; import kitchenpos.infra.ProfanityClient; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeEach; @@ -60,7 +65,7 @@ void createPriceUnderZeroException(BigDecimal price) { ThrowingCallable actual = () -> menuService.create(잘못된_가격의_메뉴); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuPriceException.class); } @DisplayName("메뉴는 메뉴 그룹에 속해야 한다.") @@ -93,7 +98,7 @@ void createMenuProductsNotExistException() { ThrowingCallable actual = () -> menuService.create(상품_없는_메뉴); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuProductNotExistException.class); } @DisplayName("중복된 메뉴상품을 가질 수 없다.") @@ -114,7 +119,7 @@ void createMenuProductsMismatchException() { ThrowingCallable actual = () -> menuService.create(중복된_상품을_포함하는_메뉴); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuProductException.class); } @DisplayName("메뉴는 수량이 부족한 메뉴상품을 포함할 수 없다.") @@ -135,7 +140,7 @@ void createMenuProductsLackQuantityException() { ThrowingCallable actual = () -> menuService.create(메뉴상품_수량_오류_메뉴); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuProductQuantityException.class); } @DisplayName("메뉴의 가격은 상품들의 합산 가격과 같거나 작아야 한다.") @@ -157,7 +162,7 @@ void createPriceException() { ThrowingCallable actual = () -> menuService.create(비싼_메뉴); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuMarginException.class); } @DisplayName("메뉴 이름에는 비속어가 포함될 수 없다.") @@ -213,7 +218,7 @@ void changePriceException(BigDecimal price) { ThrowingCallable actual = () -> menuService.changePrice(포장_전용_메뉴.getId(), 가격_변경); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuPriceException.class); } @DisplayName("상품들의 총 가격보다 높은 가격으로 변경할 수 없다.") @@ -227,7 +232,7 @@ void changePriceGreaterThanProductsPricesException() { ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 가격_변경); //then - assertThatThrownBy(actual).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(actual).isInstanceOf(MenuMarginException.class); } @DisplayName("가격 변경") @@ -268,7 +273,7 @@ void displayException() { ThrowingCallable actual = () -> menuService.display(마진_대박_맛초킹_세트.getId()); //then - assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + assertThatThrownBy(actual).isInstanceOf(MenuMarginException.class); } @DisplayName("진열") From cd82f3e732ff11cec79d16b818ce26d6bde55b88 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 13 Apr 2022 08:27:18 +0900 Subject: [PATCH 38/40] =?UTF-8?q?test:=20=EC=A3=BC=EB=AC=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B9=8C=EB=8D=94=20=ED=8C=A8=ED=84=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트 조건(given)이 명확하지 않아 테스트의 의도를 파악하기 어려움이 있었음. Builder 패턴을 적용하여 시간적 결합과 의도를 모두 표현할 수 있도록 변경 --- .../kitchenpos/application/OrderBuilder.java | 68 +++++ .../application/OrderServiceTest.java | 282 +++++++++++------- 2 files changed, 236 insertions(+), 114 deletions(-) create mode 100644 src/test/java/kitchenpos/application/OrderBuilder.java diff --git a/src/test/java/kitchenpos/application/OrderBuilder.java b/src/test/java/kitchenpos/application/OrderBuilder.java new file mode 100644 index 000000000..7a84154f2 --- /dev/null +++ b/src/test/java/kitchenpos/application/OrderBuilder.java @@ -0,0 +1,68 @@ +package kitchenpos.application; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; +import kitchenpos.domain.Order; +import kitchenpos.domain.OrderLineItem; +import kitchenpos.domain.OrderStatus; +import kitchenpos.domain.OrderTable; +import kitchenpos.domain.OrderType; + +public class OrderBuilder { + + private OrderType type; + private OrderStatus status; + private LocalDateTime orderDateTime; + private List orderLineItems; + private String deliveryAddress; + private OrderTable orderTable; + private UUID orderTableId; + + public OrderBuilder withType(OrderType type) { + this.type = type; + return this; + } + + public OrderBuilder withStatus(OrderStatus status) { + this.status = status; + return this; + } + + public OrderBuilder withOrderDateTime(LocalDateTime orderDateTime) { + this.orderDateTime = orderDateTime; + return this; + } + + public OrderBuilder withOrderLineItems(List orderLineItems) { + this.orderLineItems = orderLineItems; + return this; + } + + public OrderBuilder withDeliveryAddress(String deliveryAddress) { + this.deliveryAddress = deliveryAddress; + return this; + } + + public OrderBuilder withOrderTable(OrderTable orderTable) { + this.orderTable = orderTable; + return this; + } + + public OrderBuilder withOrderTableId(UUID orderTableId) { + this.orderTableId = orderTableId; + return this; + } + + public Order build() { + Order order = new Order(); + order.setType(type); + order.setStatus(status); + order.setOrderDateTime(orderDateTime); + order.setOrderLineItems(orderLineItems); + order.setDeliveryAddress(deliveryAddress); + order.setOrderTable(orderTable); + order.setOrderTableId(orderTableId); + return order; + } +} diff --git a/src/test/java/kitchenpos/application/OrderServiceTest.java b/src/test/java/kitchenpos/application/OrderServiceTest.java index 039fafe98..f11b354f2 100644 --- a/src/test/java/kitchenpos/application/OrderServiceTest.java +++ b/src/test/java/kitchenpos/application/OrderServiceTest.java @@ -1,13 +1,15 @@ package kitchenpos.application; -import static kitchenpos.application.MenuFixture.뿌링클_세트; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.UUID; import java.util.stream.Stream; import kitchenpos.domain.Menu; import kitchenpos.domain.MenuRepository; @@ -20,6 +22,7 @@ import kitchenpos.domain.OrderType; import kitchenpos.domain.exception.OrderDeliveryAddressException; import kitchenpos.domain.exception.OrderDisplayException; +import kitchenpos.domain.exception.OrderFromEmptyOrderTableException; import kitchenpos.domain.exception.OrderInvalidQuantityException; import kitchenpos.domain.exception.OrderLineItemNotExistException; import kitchenpos.domain.exception.OrderLineItemNotMatchException; @@ -47,19 +50,26 @@ class OrderServiceTest { private OrderService orderService; + private Menu 맛초킹_세트; + private Menu 뿌링클_세트; + @BeforeEach void setUp() { orderService = new OrderService(orderRepository, menuRepository, orderTableRepository, kitchenridersClient); + 뿌링클_세트 = menuRepository.save(MenuFixture.뿌링클_세트); + 맛초킹_세트 = menuRepository.save(MenuFixture.맛초킹_세트); } @DisplayName("주문 유형이 반드시 있어야 한다.") @Test void createOrderTypeException() { //given - Order order = new Order(); + Order 주문_유형_없는_주문 = 신규_주문() + .withType(null) + .build(); //when - ThrowingCallable actual = () -> orderService.create(order); + ThrowingCallable actual = () -> orderService.create(주문_유형_없는_주문); //then assertThatThrownBy(actual).isInstanceOf(OrderTypeNotExistException.class); @@ -70,7 +80,9 @@ void createOrderTypeException() { @NullAndEmptySource void createOrderHasNoMenuException(List orderLineItems) { //given - Order 상품_없는_주문 = 신규_배달_주문(orderLineItems); + Order 상품_없는_주문 = 신규_배달_주문() + .withOrderLineItems(orderLineItems) + .build(); //when ThrowingCallable actual = () -> orderService.create(상품_없는_주문); @@ -83,8 +95,12 @@ void createOrderHasNoMenuException(List orderLineItems) { @Test void createOrderInvalidMenuException() { //given - OrderLineItem 등록_되지_않은_상품 = 주문_항목_1개(new Menu()); - Order 등록되지_않은_상품_주문 = 신규_배달_주문(Collections.singletonList(등록_되지_않은_상품)); + Menu 등록되지_않은_메뉴 = new Menu(); + OrderLineItem 등록_되지_않은_상품 = 주문_항목_1개(등록되지_않은_메뉴); + + Order 등록되지_않은_상품_주문 = 신규_배달_주문() + .withOrderLineItems(Collections.singletonList(등록_되지_않은_상품)) + .build(); //when ThrowingCallable actual = () -> orderService.create(등록되지_않은_상품_주문); @@ -98,9 +114,11 @@ void createOrderInvalidMenuException() { @EnumSource(value = OrderType.class, names = {"DELIVERY", "TAKEOUT"}) void createOrderInvalidQuantityException(OrderType orderType) { //given - Menu menu = menuRepository.save(뿌링클_세트); - OrderLineItem 모자란_수량 = 주문_항목(menu, -1); - Order 신규_배달_주문 = 신규_주문(orderType, Collections.singletonList(모자란_수량)); + OrderLineItem 모자란_수량 = 주문_항목(뿌링클_세트, -1); + Order 신규_배달_주문 = 신규_주문() + .withType(orderType) + .withOrderLineItems(Collections.singletonList(모자란_수량)) + .build(); //when ThrowingCallable actual = () -> orderService.create(신규_배달_주문); @@ -114,7 +132,9 @@ void createOrderInvalidQuantityException(OrderType orderType) { void createOrderNotDisplayedMenuException() { //given List 진열되지_않은_메뉴_상품 = 메뉴_뿌링클_1개(new Menu()); - Order 진열되지_않은_상품_주문 = 신규_배달_주문(진열되지_않은_메뉴_상품); + Order 진열되지_않은_상품_주문 = 신규_배달_주문() + .withOrderLineItems(진열되지_않은_메뉴_상품) + .build(); //when ThrowingCallable actual = () -> orderService.create(진열되지_않은_상품_주문); @@ -127,10 +147,10 @@ void createOrderNotDisplayedMenuException() { @Test void createOrderMismatchPriceException() { //given - Menu 뿌링클_세트 = menuRepository.save(뿌링클_세트()); - List 모자란_금액 = Collections.singletonList(주문_항목_1개(뿌링클_세트, 8_000)); - Order 모자란_금액_주문 = 신규_배달_주문(모자란_금액); + Order 모자란_금액_주문 = 신규_배달_주문() + .withOrderLineItems(모자란_금액) + .build(); //when ThrowingCallable actual = () -> orderService.create(모자란_금액_주문); @@ -144,8 +164,9 @@ void createOrderMismatchPriceException() { @NullAndEmptySource void createDeliveryOrderHasNoAddressException(String deliveryAddress) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - Order 주소_없는_배달_주문 = 신규_배달_주문(뿌링클_1개, deliveryAddress); + Order 주소_없는_배달_주문 = 신규_배달_주문() + .withDeliveryAddress(deliveryAddress) + .build(); //when ThrowingCallable actual = () -> orderService.create(주소_없는_배달_주문); @@ -158,30 +179,28 @@ void createDeliveryOrderHasNoAddressException(String deliveryAddress) { @Test void createEatInException() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - Order 착석하지_않고_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); - OrderTable orderTable1 = new OrderTable(); - orderTable1.setEmpty(true); - OrderTable orderTable = orderTableRepository.save(orderTable1); - 착석하지_않고_주문.setOrderTable(orderTable); - 착석하지_않고_주문.setOrderTableId(orderTable.getId()); + OrderTable 착석하지_않은_식탁 = 착석하지_않은_식탁(); + Order 착석하지_않고_주문 = 신규_매장_주문() + .withOrderTableId(착석하지_않은_식탁.getId()) + + .build(); //when ThrowingCallable actual = () -> orderService.create(착석하지_않고_주문); //then - assertThatThrownBy(actual).isInstanceOf(IllegalStateException.class); + assertThatThrownBy(actual).isInstanceOf(OrderFromEmptyOrderTableException.class); } @DisplayName("매장 식당 주문") @Test void createOrderEatIn() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - OrderTable orderTable = orderTableRepository.save(착석한_식탁()); + OrderTable 착석한_식탁 = 착석한_식탁(); - Order 매장_식사_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); - 매장_식사_주문.setOrderTableId(orderTable.getId()); + Order 매장_식사_주문 = 신규_매장_주문() + .withOrderTableId(착석한_식탁.getId()) + .build(); //when Order order = orderService.create(매장_식사_주문); @@ -190,7 +209,7 @@ void createOrderEatIn() { assertAll( () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), () -> assertThat(order.getType()).isEqualTo(OrderType.EAT_IN), - () -> assertThat(order.getOrderTable().getId()).isEqualTo(orderTable.getId()) + () -> assertThat(order.getOrderTable().getId()).isEqualTo(착석한_식탁.getId()) ); } @@ -198,9 +217,7 @@ void createOrderEatIn() { @Test void createOrderTakeout() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - - Order 포장_식사_주문 = 신규_주문(OrderType.TAKEOUT, 뿌링클_1개); + Order 포장_식사_주문 = 신규_포장_주문().build(); //when Order order = orderService.create(포장_식사_주문); @@ -216,9 +233,11 @@ void createOrderTakeout() { @Test void createOrderDelivery() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + String deliveryAddress = "우리집"; - Order 배달_식사_주문 = 신규_배달_주문(뿌링클_1개, "우리집"); + Order 배달_식사_주문 = 신규_배달_주문() + .withDeliveryAddress(deliveryAddress) + .build(); //when Order order = orderService.create(배달_식사_주문); @@ -227,7 +246,7 @@ void createOrderDelivery() { assertAll( () -> assertThat(order.getStatus()).isEqualTo(OrderStatus.WAITING), () -> assertThat(order.getType()).isEqualTo(OrderType.DELIVERY), - () -> assertThat(order.getDeliveryAddress()).isEqualTo("우리집") + () -> assertThat(order.getDeliveryAddress()).isEqualTo(deliveryAddress) ); } @@ -236,9 +255,12 @@ void createOrderDelivery() { @EnumSource(value = OrderStatus.class, names = {"WAITING"}, mode = Mode.EXCLUDE) void accept(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_배달_주문 = 신규_배달_주문() + .withDeliveryAddress("우리집") + .withStatus(orderStatus) + .build(); - Order 대기중이_아닌_배달_식사_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); + Order 대기중이_아닌_배달_식사_주문 = orderRepository.save(신규_배달_주문); //when ThrowingCallable actual = () -> orderService.accept(대기중이_아닌_배달_식사_주문.getId()); @@ -251,9 +273,11 @@ void accept(OrderStatus orderStatus) { @Test void acceptOrderDelivery() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_배달_주문 = 신규_배달_주문() + .withDeliveryAddress("우리집") + .build(); - Order 대기중인_배달_식사_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집")); + Order 대기중인_배달_식사_주문 = orderRepository.save(신규_배달_주문); //when Order actual = orderService.accept(대기중인_배달_식사_주문.getId()); @@ -267,9 +291,11 @@ void acceptOrderDelivery() { @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) void accept(OrderType orderType) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_주문 = 신규_주문() + .withType(orderType) + .build(); - Order 대기중인_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, OrderStatus.WAITING)); + Order 대기중인_주문 = orderRepository.save(신규_주문); //when Order actual = orderService.accept(대기중인_주문.getId()); @@ -283,9 +309,11 @@ void accept(OrderType orderType) { @EnumSource(value = OrderStatus.class, names = {"ACCEPTED"}, mode = Mode.EXCLUDE) void serveException(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_주문 = 신규_주문() + .withStatus(orderStatus) + .build(); - Order 수락되지_않은_주문 = orderRepository.save(신규_주문(OrderType.EAT_IN, 뿌링클_1개, orderStatus)); + Order 수락되지_않은_주문 = orderRepository.save(신규_주문); //when ThrowingCallable actual = () -> orderService.serve(수락되지_않은_주문.getId()); @@ -298,9 +326,11 @@ void serveException(OrderStatus orderStatus) { @Test void serve() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_주문 = 신규_주문() + .withStatus(OrderStatus.ACCEPTED) + .build(); - Order 수락된_주문 = orderRepository.save(신규_주문(OrderType.EAT_IN, 뿌링클_1개, OrderStatus.ACCEPTED)); + Order 수락된_주문 = orderRepository.save(신규_주문); //when Order actual = orderService.serve(수락된_주문.getId()); @@ -314,9 +344,12 @@ void serve() { @EnumSource(value = OrderType.class, names = {"EAT_IN", "TAKEOUT"}) void startDeliveryOrderTypeException(OrderType orderType) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_주문 = 신규_주문() + .withStatus(OrderStatus.SERVED) + .withType(orderType) + .build(); - Order 배달이_아닌_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, OrderStatus.SERVED)); + Order 배달이_아닌_주문 = orderRepository.save(신규_주문); //when ThrowingCallable actual = () -> orderService.startDelivery(배달이_아닌_주문.getId()); @@ -330,9 +363,11 @@ void startDeliveryOrderTypeException(OrderType orderType) { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERING", "DELIVERED", "COMPLETED"}) void startDeliveryOrderStatusException(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 배달_주문 = 신규_배달_주문() + .withStatus(orderStatus) + .build(); - Order 조리_완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); + Order 조리_완료되지_않은_배달_주문 = orderRepository.save(배달_주문); //when ThrowingCallable actual = () -> orderService.startDelivery(조리_완료되지_않은_배달_주문.getId()); @@ -345,9 +380,11 @@ void startDeliveryOrderStatusException(OrderStatus orderStatus) { @Test void startDelivery() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 배달_주문 = 신규_배달_주문() + .withStatus(OrderStatus.SERVED) + .build(); - Order 조리_완료된_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.SERVED)); + Order 조리_완료된_배달_주문 = orderRepository.save(배달_주문); //when Order actual = orderService.startDelivery(조리_완료된_배달_주문.getId()); @@ -361,9 +398,11 @@ void startDelivery() { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERED", "COMPLETED"}) void completeDeliveryOrderStatusException(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_배달_주문 = 신규_배달_주문() + .withStatus(orderStatus) + .build(); - Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); + Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문); //when ThrowingCallable actual = () -> orderService.completeDelivery(배달중인_배달_주문.getId()); @@ -376,9 +415,11 @@ void completeDeliveryOrderStatusException(OrderStatus orderStatus) { @Test void completeDelivery() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_배달_주문 = 신규_배달_주문() + .withStatus(OrderStatus.DELIVERING) + .build(); - Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.DELIVERING)); + Order 배달중인_배달_주문 = orderRepository.save(신규_배달_주문); //when Order actual = orderService.completeDelivery(배달중인_배달_주문.getId()); @@ -392,9 +433,11 @@ void completeDelivery() { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "SERVED", "DELIVERING", "COMPLETED"}) void completeDeliveryStatusException(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_배달_주문 = 신규_배달_주문() + .withStatus(orderStatus) + .build(); - Order 배달완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", orderStatus)); + Order 배달완료되지_않은_배달_주문 = orderRepository.save(신규_배달_주문); //when ThrowingCallable actual = () -> orderService.complete(배달완료되지_않은_배달_주문.getId()); @@ -407,9 +450,11 @@ void completeDeliveryStatusException(OrderStatus orderStatus) { @Test void completeDeliveryOrder() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_배달_주문 = 신규_배달_주문() + .withStatus(OrderStatus.DELIVERED) + .build(); - Order 배달완료된_배달_주문 = orderRepository.save(신규_배달_주문(뿌링클_1개, "우리집", OrderStatus.DELIVERED)); + Order 배달완료된_배달_주문 = orderRepository.save(신규_배달_주문); //when Order actual = orderService.complete(배달완료된_배달_주문.getId()); @@ -423,9 +468,11 @@ void completeDeliveryOrder() { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) void completeTakeoutOrderStatusException(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_포장_주문 = 신규_포장_주문() + .withStatus(orderStatus) + .build(); - Order 조리완료되지_않은_포장_주문 = orderRepository.save(신규_주문(OrderType.TAKEOUT, 뿌링클_1개, orderStatus)); + Order 조리완료되지_않은_포장_주문 = orderRepository.save(신규_포장_주문); //when ThrowingCallable actual = () -> orderService.complete(조리완료되지_않은_포장_주문.getId()); @@ -439,9 +486,11 @@ void completeTakeoutOrderStatusException(OrderStatus orderStatus) { @EnumSource(value = OrderStatus.class, names = {"WAITING", "ACCEPTED", "DELIVERED", "DELIVERING", "COMPLETED"}) void completeEatInStatusException(OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_포장_주문 = 신규_포장_주문() + .withStatus(orderStatus) + .build(); - Order 조리완료되지_않은_매장_주문 = orderRepository.save(신규_주문(OrderType.TAKEOUT, 뿌링클_1개, orderStatus)); + Order 조리완료되지_않은_매장_주문 = orderRepository.save(신규_포장_주문); //when ThrowingCallable actual = () -> orderService.complete(조리완료되지_않은_매장_주문.getId()); @@ -455,9 +504,12 @@ void completeEatInStatusException(OrderStatus orderStatus) { @MethodSource("completeTakeoutOrDelivery") void completeTakeoutOrDeliveryOrder(OrderType orderType, OrderStatus orderStatus) { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); + Order 신규_주문 = 신규_주문() + .withType(orderType) + .withStatus(orderStatus) + .build(); - Order 조리완료된_주문 = orderRepository.save(신규_주문(orderType, 뿌링클_1개, orderStatus)); + Order 조리완료된_주문 = orderRepository.save(신규_주문); //when Order actual = orderService.complete(조리완료된_주문.getId()); @@ -477,12 +529,12 @@ private static Stream completeTakeoutOrDelivery() { @Test void completeEatInOrder() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - - Order 신규_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개, OrderStatus.SERVED); - OrderTable orderTable = orderTableRepository.save(착석한_식탁()); - 신규_주문.setOrderTableId(orderTable.getId()); - 신규_주문.setOrderTable(orderTable); + OrderTable 착석한_식탁 = 착석한_식탁(); + Order 신규_주문 = 신규_매장_주문() + .withOrderTableId(착석한_식탁.getId()) + .withOrderTable(착석한_식탁) + .withStatus(OrderStatus.SERVED) + .build(); Order 조리완료된_주문 = orderRepository.save(신규_주문); @@ -497,20 +549,13 @@ void completeEatInOrder() { ); } - private List 메뉴_뿌링클_1개(Menu menu) { - Menu 뿌링클_세트 = menuRepository.save(menu); - return Collections.singletonList(주문_항목_1개(뿌링클_세트)); - } - @DisplayName("모든 주문 조회") @Test void findAll() { //given - List 뿌링클_1개 = 메뉴_뿌링클_1개(뿌링클_세트()); - - Order 매장_주문 = 신규_주문(OrderType.EAT_IN, 뿌링클_1개); - Order 포장_주문 = 신규_주문(OrderType.TAKEOUT, 뿌링클_1개); - Order 배달_주문 = 신규_주문(OrderType.DELIVERY, 뿌링클_1개); + Order 매장_주문 = 신규_매장_주문().build(); + Order 포장_주문 = 신규_포장_주문().build(); + Order 배달_주문 = 신규_배달_주문().build(); orderRepository.save(매장_주문); orderRepository.save(포장_주문); @@ -523,43 +568,17 @@ void findAll() { assertThat(actual).hasSize(3); } - private OrderTable 착석한_식탁() { - OrderTable orderTable = new OrderTable(); - orderTable.setEmpty(false); - return orderTable; - } - - private Menu 뿌링클_세트() { - Menu menu = new Menu(); - menu.setDisplayed(true); - menu.setPrice(BigDecimal.valueOf(10_000)); - return menu; - } - - private Order 신규_주문(OrderType orderType, List orderLineItems) { - return 신규_주문(orderType, orderLineItems, OrderStatus.WAITING); - } - - private Order 신규_주문(OrderType orderType, List orderLineItems, OrderStatus orderStatus) { - Order order = new Order(); - order.setType(orderType); - order.setOrderLineItems(orderLineItems); - order.setStatus(orderStatus); - return order; - } - private Order 신규_배달_주문(List orderLineItems, String deliveryAddress, OrderStatus orderStatus) { - Order order = 신규_주문(OrderType.DELIVERY, orderLineItems, orderStatus); - order.setDeliveryAddress(deliveryAddress); - return order; - } - - private Order 신규_배달_주문(List orderLineItems, String deliveryAddress) { - return 신규_배달_주문(orderLineItems, deliveryAddress, OrderStatus.WAITING); + private OrderTable 착석하지_않은_식탁() { + OrderTable orderTable = new OrderTable(); + orderTable.setEmpty(true); + return orderTableRepository.save(orderTable); } - private Order 신규_배달_주문(List orderLineItems) { - return 신규_배달_주문(orderLineItems, "독도"); + private OrderTable 착석한_식탁() { + OrderTable orderTable = new OrderTable(); + orderTable.setEmpty(false); + return orderTableRepository.save(orderTable); } public static OrderLineItem 주문_항목_1개(Menu menu) { @@ -583,4 +602,39 @@ void findAll() { return orderLineItem; } + private List 메뉴_뿌링클_1개(Menu menu) { + Menu 뿌링클_세트 = menuRepository.save(menu); + return Collections.singletonList(주문_항목_1개(뿌링클_세트)); + } + + private OrderBuilder 신규_매장_주문() { + return 신규_주문() + .withType(OrderType.EAT_IN) + .withDeliveryAddress(null); + } + + private OrderBuilder 신규_포장_주문() { + return 신규_주문() + .withType(OrderType.TAKEOUT) + .withOrderTableId(null) + .withDeliveryAddress(null); + } + + private OrderBuilder 신규_배달_주문() { + return 신규_주문() + .withType(OrderType.DELIVERY) + .withOrderTableId(null); + } + + private OrderBuilder 신규_주문() { + return new OrderBuilder() + .withOrderDateTime(LocalDateTime.now()) + .withStatus(OrderStatus.WAITING) + .withOrderLineItems(Arrays.asList( + 주문_항목(뿌링클_세트, 1, 11_000), + 주문_항목(맛초킹_세트, 1, 11_000)) + ) + .withDeliveryAddress("독도") + .withOrderTableId(UUID.randomUUID()); + } } From fc329aed862762ee0fe1797585f50be2002d32e5 Mon Sep 17 00:00:00 2001 From: yongju Date: Wed, 13 Apr 2022 08:36:42 +0900 Subject: [PATCH 39/40] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=9E=A5=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=20=EB=B9=88=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=EC=98=88=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kitchenpos/application/OrderService.java | 27 ++++++++++++++----- .../OrderFromEmptyOrderTableException.java | 10 +++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/main/java/kitchenpos/domain/exception/OrderFromEmptyOrderTableException.java diff --git a/src/main/java/kitchenpos/application/OrderService.java b/src/main/java/kitchenpos/application/OrderService.java index e4110e357..fbe91174d 100644 --- a/src/main/java/kitchenpos/application/OrderService.java +++ b/src/main/java/kitchenpos/application/OrderService.java @@ -1,8 +1,25 @@ package kitchenpos.application; -import kitchenpos.domain.*; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; +import kitchenpos.domain.Menu; +import kitchenpos.domain.MenuRepository; +import kitchenpos.domain.Order; +import kitchenpos.domain.OrderLineItem; +import kitchenpos.domain.OrderRepository; +import kitchenpos.domain.OrderStatus; +import kitchenpos.domain.OrderTable; +import kitchenpos.domain.OrderTableRepository; +import kitchenpos.domain.OrderType; import kitchenpos.domain.exception.OrderDeliveryAddressException; import kitchenpos.domain.exception.OrderDisplayException; +import kitchenpos.domain.exception.OrderFromEmptyOrderTableException; import kitchenpos.domain.exception.OrderInvalidQuantityException; import kitchenpos.domain.exception.OrderLineItemNotExistException; import kitchenpos.domain.exception.OrderLineItemNotMatchException; @@ -12,13 +29,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.*; -import java.util.stream.Collectors; - @Service public class OrderService { + private final OrderRepository orderRepository; private final MenuRepository menuRepository; private final OrderTableRepository orderTableRepository; @@ -93,7 +106,7 @@ public Order create(final Order request) { final OrderTable orderTable = orderTableRepository.findById(request.getOrderTableId()) .orElseThrow(NoSuchElementException::new); if (orderTable.isEmpty()) { - throw new IllegalStateException(); + throw new OrderFromEmptyOrderTableException(); } order.setOrderTable(orderTable); } diff --git a/src/main/java/kitchenpos/domain/exception/OrderFromEmptyOrderTableException.java b/src/main/java/kitchenpos/domain/exception/OrderFromEmptyOrderTableException.java new file mode 100644 index 000000000..ecfd8dbdd --- /dev/null +++ b/src/main/java/kitchenpos/domain/exception/OrderFromEmptyOrderTableException.java @@ -0,0 +1,10 @@ +package kitchenpos.domain.exception; + +public class OrderFromEmptyOrderTableException extends IllegalStateException { + + private static final String DEFAULT_MESSAGE = "착석 후 주문 가능합니다."; + + public OrderFromEmptyOrderTableException() { + super(DEFAULT_MESSAGE); + } +} From c3ea86e17d945c9ab2b8c685a964f019f44b1292 Mon Sep 17 00:00:00 2001 From: yongju Date: Thu, 14 Apr 2022 08:04:17 +0900 Subject: [PATCH 40/40] =?UTF-8?q?test:=20=EB=A9=94=EB=89=B4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B9=8C=EB=8D=94=20=ED=8C=A8=ED=84=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 시간적 결합을 제거하고 테스트의 의도를 코드로 표현 --- .../application/MenuServiceTest.java | 114 ++++++------------ 1 file changed, 38 insertions(+), 76 deletions(-) diff --git a/src/test/java/kitchenpos/application/MenuServiceTest.java b/src/test/java/kitchenpos/application/MenuServiceTest.java index 5b3181662..a5372a685 100644 --- a/src/test/java/kitchenpos/application/MenuServiceTest.java +++ b/src/test/java/kitchenpos/application/MenuServiceTest.java @@ -1,6 +1,5 @@ package kitchenpos.application; -import static kitchenpos.application.MenuGroupFixture.세트메뉴; import static kitchenpos.application.MenuProductFixture.맛초킹_1개; import static kitchenpos.application.MenuProductFixture.콜라_1개; import static kitchenpos.application.MenuProductFixture.콜라_수량_오류; @@ -12,15 +11,13 @@ import java.math.BigDecimal; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; -import java.util.UUID; import kitchenpos.domain.Menu; import kitchenpos.domain.MenuGroup; import kitchenpos.domain.MenuGroupRepository; -import kitchenpos.domain.MenuProduct; import kitchenpos.domain.MenuRepository; -import kitchenpos.domain.Product; import kitchenpos.domain.ProductRepository; import kitchenpos.domain.exception.MenuMarginException; import kitchenpos.domain.exception.MenuPriceException; @@ -45,10 +42,14 @@ class MenuServiceTest { private final ProfanityClient profanityClient = new FakeProfanityClient(); private MenuService menuService; + private MenuGroup 세트메뉴; @BeforeEach void setUp() { menuService = new MenuService(menuRepository, menuGroupRepository, productRepository, profanityClient); + productRepository.save(맛초킹); + productRepository.save(콜라); + 세트메뉴 = menuGroupRepository.save(MenuGroupFixture.세트메뉴); } @DisplayName("메뉴의 가격은 0원 이상이어야 한다.") @@ -73,7 +74,7 @@ void createPriceUnderZeroException(BigDecimal price) { void createMenuGroupNotExistException() { //given Menu 메뉴_그룹에_속하지_않은_메뉴 = 메뉴생성() - .withMenuGroup(null) + .withMenuGroupId(null) .build(); //when @@ -87,11 +88,8 @@ void createMenuGroupNotExistException() { @Test void createMenuProductsNotExistException() { //given - MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - Menu 상품_없는_메뉴 = 메뉴생성() - .withMenuGroup(세트_메뉴) - .withMenuGroupId(세트_메뉴.getId()) + .withMenuProducts(Collections.emptyList()) .build(); //when @@ -105,13 +103,7 @@ void createMenuProductsNotExistException() { @Test void createMenuProductsMismatchException() { //given - MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - productRepository.save(맛초킹); - productRepository.save(콜라); - Menu 중복된_상품을_포함하는_메뉴 = 메뉴생성() - .withMenuGroup(세트_메뉴) - .withMenuGroupId(세트_메뉴.getId()) .withMenuProducts(맛초킹_1개, 맛초킹_1개, 콜라_1개) .build(); @@ -126,13 +118,7 @@ void createMenuProductsMismatchException() { @Test void createMenuProductsLackQuantityException() { //given - MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - productRepository.save(맛초킹); - productRepository.save(콜라); - Menu 메뉴상품_수량_오류_메뉴 = 메뉴생성() - .withMenuGroup(세트_메뉴) - .withMenuGroupId(세트_메뉴.getId()) .withMenuProducts(맛초킹_1개, 콜라_수량_오류) .build(); @@ -147,15 +133,8 @@ void createMenuProductsLackQuantityException() { @Test void createPriceException() { //given - MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - productRepository.save(맛초킹); - productRepository.save(콜라); - Menu 비싼_메뉴 = 메뉴생성() .withPrice(15_000L) - .withMenuGroup(세트_메뉴) - .withMenuGroupId(세트_메뉴.getId()) - .withMenuProducts(맛초킹_1개, 콜라_1개) .build(); //when @@ -169,14 +148,8 @@ void createPriceException() { @Test void createNameException() { //given - MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - productRepository.save(맛초킹); - productRepository.save(콜라); - Menu 비속어_메뉴 = 메뉴생성() .withName("비속어") - .withMenuGroupId(세트_메뉴.getId()) - .withMenuProducts(맛초킹_1개, 콜라_1개) .build(); //when @@ -190,7 +163,7 @@ void createNameException() { @Test void create() { //given - Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); + Menu 맛초킹_세트 = 메뉴생성().build(); //when Menu menu = menuService.create(맛초킹_세트); @@ -210,12 +183,12 @@ void create() { @NullSource void changePriceException(BigDecimal price) { //given - Menu 포장_전용_메뉴 = menuRepository.save(메뉴생성().build()); + Menu 맛초킹_세트 = 맛초킹_세트_생성(); - Menu 가격_변경 = 메뉴_생성(price); + Menu 가격_변경 = 가격_변경(price); //when - ThrowingCallable actual = () -> menuService.changePrice(포장_전용_메뉴.getId(), 가격_변경); + ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 가격_변경); //then assertThatThrownBy(actual).isInstanceOf(MenuPriceException.class); @@ -225,8 +198,10 @@ void changePriceException(BigDecimal price) { @Test void changePriceGreaterThanProductsPricesException() { //given - Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); - Menu 가격_변경 = 메뉴_생성(50_000); + Menu 맛초킹_세트 = 맛초킹_세트_생성(); + + BigDecimal 인상된_가격 = 맛초킹_세트.getPrice().add(BigDecimal.valueOf(10_000L)); + Menu 가격_변경 = 가격_변경(인상된_가격); //when ThrowingCallable actual = () -> menuService.changePrice(맛초킹_세트.getId(), 가격_변경); @@ -239,22 +214,24 @@ void changePriceGreaterThanProductsPricesException() { @Test void changePrice() { //given - Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); - Menu 가격_인하 = 메뉴_생성(10_500); + Menu 맛초킹_세트 = 맛초킹_세트_생성(); + + BigDecimal 인하된_가격 = 맛초킹_세트.getPrice().subtract(BigDecimal.valueOf(10_000L)); + Menu 가격_인하 = 가격_변경(인하된_가격); //when Menu menu = menuService.changePrice(맛초킹_세트.getId(), 가격_인하); BigDecimal actual = menu.getPrice(); //then - assertThat(actual).isEqualTo(BigDecimal.valueOf(10_500L)); + assertThat(actual).isEqualTo(인하된_가격); } @DisplayName("등록되지 않은 메뉴는 진열할 수 없다.") @Test void displayNotExistException() { //given - Menu 없는_메뉴 = new MenuBuilder().build(); + Menu 없는_메뉴 = 등록_되지_않은_메뉴(); //when ThrowingCallable actual = () -> menuService.display(없는_메뉴.getId()); @@ -276,11 +253,11 @@ void displayException() { assertThatThrownBy(actual).isInstanceOf(MenuMarginException.class); } - @DisplayName("진열") + @DisplayName("메뉴를 진열한다.") @Test void display() { //given - Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); + Menu 맛초킹_세트 = 맛초킹_세트_생성(); //when Menu menu = menuService.display(맛초킹_세트.getId()); @@ -293,7 +270,7 @@ void display() { @Test void hideException() { //given - Menu 없는_메뉴 = new MenuBuilder().build(); + Menu 없는_메뉴 = 등록_되지_않은_메뉴(); //when ThrowingCallable actual = () -> menuService.hide(없는_메뉴.getId()); @@ -302,17 +279,17 @@ void hideException() { assertThatThrownBy(actual).isInstanceOf(NoSuchElementException.class); } - @DisplayName("진열 제외") + @DisplayName("메뉴를 숨긴다.") @Test void hide() { //given - Menu 맛초킹_세트 = 맛초킹_세트_생성(11_000); + Menu 맛초킹_세트 = 맛초킹_세트_생성(); //when - Menu menu = menuService.hide(맛초킹_세트.getId()); + Menu actual = menuService.hide(맛초킹_세트.getId()); //then - assertThat(menu.isDisplayed()).isFalse(); + assertThat(actual.isDisplayed()).isFalse(); } @DisplayName("모든 메뉴 조회") @@ -329,37 +306,22 @@ void findAll() { assertThat(actual).hasSize(2); } - private Menu 맛초킹_세트_생성(int price) { - MenuGroup 세트_메뉴 = menuGroupRepository.save(세트메뉴); - Product 맛초킹 = productRepository.save(ProductFixture.맛초킹); - Product 콜라 = productRepository.save(ProductFixture.콜라); + private Menu 등록_되지_않은_메뉴() { + return new MenuBuilder().build(); + } - MenuProduct 맛초킹1개 = 메뉴_상품_생성(맛초킹); - MenuProduct 콜라1개 = 메뉴_상품_생성(콜라); + private Menu 맛초킹_세트_생성() { + return 맛초킹_세트_생성(11_000); + } + private Menu 맛초킹_세트_생성(int price) { Menu 맛초킹_세트 = 메뉴생성() - .withMenuGroupId(세트_메뉴.getId()) - .withMenuGroup(세트메뉴) - .withMenuProducts(Arrays.asList(맛초킹1개, 콜라1개)) - .withName("맛초킹 세트") .withPrice(price) .build(); return menuRepository.save(맛초킹_세트); } - private MenuProduct 메뉴_상품_생성(Product product) { - MenuProduct menuProduct = new MenuProduct(); - menuProduct.setQuantity(1L); - menuProduct.setProduct(product); - menuProduct.setProductId(product.getId()); - return menuProduct; - } - - private Menu 메뉴_생성(int price) { - return 메뉴_생성(BigDecimal.valueOf(price)); - } - - private Menu 메뉴_생성(BigDecimal price) { + private Menu 가격_변경(BigDecimal price) { return new MenuBuilder() .withPrice(price) .build(); @@ -367,8 +329,8 @@ void findAll() { private MenuBuilder 메뉴생성() { return new MenuBuilder() - .withMenuGroup(new MenuGroup()) - .withMenuGroupId(UUID.randomUUID()) + .withMenuGroup(세트메뉴) + .withMenuGroupId(세트메뉴.getId()) .withName("맛초킹 세트") .withDisplayed(true) .withMenuProducts(Arrays.asList(맛초킹_1개, 콜라_1개))