Skip to content

Commit 30f8edb

Browse files
author
seungjoo.jeong
committed
feat(test) usecase에 대한 테스트코드 작성
- usecase 테스트코드 작성 - 테스트 도우미 fixtures, accessor 추가
1 parent a651a16 commit 30f8edb

12 files changed

+353
-18
lines changed

src/main/java/kitchenpos/menu/adapter/in/MenuDisplayingRearranger.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public MenuDisplayingRearranger(final MenuUseCase menuUseCase) {
1111
this.menuUseCase = menuUseCase;
1212
}
1313

14-
public void rearrange(final UUID productId) {
14+
public void execute(final UUID productId) {
1515
menuUseCase.rearrangeDisplaying(productId);
1616
}
1717
}

src/main/java/kitchenpos/product/adapter/out/DefaultProductPriceChangeEventPublisher.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package kitchenpos.product.adapter.out;
22

3+
import static kitchenpos.support.ParameterValidateUtils.checkNotNull;
4+
35
import java.util.UUID;
46
import kitchenpos.menu.adapter.in.MenuDisplayingRearranger;
57
import kitchenpos.product.application.port.out.ProductPriceChangeEventPublisher;
8+
import kitchenpos.product.support.constant.Name;
69

710
public class DefaultProductPriceChangeEventPublisher implements ProductPriceChangeEventPublisher {
811

@@ -14,6 +17,8 @@ public DefaultProductPriceChangeEventPublisher(final MenuDisplayingRearranger re
1417

1518
@Override
1619
public void publish(final UUID id) {
17-
rearranger.rearrange(id);
20+
checkNotNull(id, Name.ID);
21+
22+
rearranger.execute(id);
1823
}
1924
}

src/main/java/kitchenpos/product/application/DefaultProductRegistrationUseCase.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package kitchenpos.product.application;
22

3+
import static kitchenpos.product.support.constant.Name.PRICE;
4+
import static kitchenpos.support.ParameterValidateUtils.checkNotNull;
5+
36
import kitchenpos.product.application.port.in.ProductRegistrationUseCase;
47
import kitchenpos.product.application.port.out.ProductNewRepository;
58
import kitchenpos.product.domain.Name;
9+
import kitchenpos.product.domain.ProductName;
610
import kitchenpos.product.domain.ProductNameFactory;
711
import kitchenpos.product.domain.ProductNew;
812
import kitchenpos.product.domain.ProductPrice;
@@ -21,10 +25,15 @@ public DefaultProductRegistrationUseCase(final ProductNameFactory productNameFac
2125
}
2226

2327
@Override
24-
public void register(final Name productNameCandidate, final ProductPrice price) {
28+
public ProductDTO register(final Name productNameCandidate, final ProductPrice price) {
29+
checkNotNull(productNameCandidate, "productNameCandidate");
30+
checkNotNull(price, PRICE);
31+
32+
final ProductName productName = productNameFactory.create(productNameCandidate);
33+
2534
final ProductNew product
26-
= ProductNew.newOf(productNameFactory.create(productNameCandidate), price);
35+
= repository.save(ProductNew.newOf(productName, price));
2736

28-
repository.save(product);
37+
return new ProductDTO(product);
2938
}
3039
}

src/main/java/kitchenpos/product/application/ProductDTO.java

+4
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ public String toString() {
3131
.add("name", name)
3232
.toString();
3333
}
34+
35+
public UUID getId() {
36+
return id;
37+
}
3438
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package kitchenpos.product.application.port.in;
22

3+
import kitchenpos.product.application.ProductDTO;
4+
import kitchenpos.product.application.exception.ContainsProfanityException;
35
import kitchenpos.product.domain.Name;
46
import kitchenpos.product.domain.ProductPrice;
57

68
public interface ProductRegistrationUseCase {
79

810
/**
9-
* @throws IllegalArgumentException nameCandidate에 비속어가 포함되어 있을 때
11+
* @throws ContainsProfanityException nameCandidate에 비속어가 포함되어 있을 때
1012
*/
11-
void register(final Name productNameCandidate, final ProductPrice price);
13+
ProductDTO register(final Name productNameCandidate, final ProductPrice price);
1214
}

src/test/java/kitchenpos/product/Fixtures.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
package kitchenpos.product;
22

33
import kitchenpos.product.domain.Name;
4+
import kitchenpos.product.domain.ProductNameAccessor;
5+
import kitchenpos.product.domain.ProductNew;
46
import kitchenpos.product.domain.ProductPrice;
57

68
public final class Fixtures {
79

810
public static final String TEST_NAME = "닭강정";
911
public static final Name VALID_NAME = new Name(TEST_NAME);
10-
12+
1113
public static final long TEST_PRICE_VALUE = 1_000L;
12-
public static final ProductPrice VALID_PRODUCT_PRIECE = ProductPrice.of(TEST_PRICE_VALUE);
14+
public static final ProductPrice VALID_PRODUCT_PRICE = ProductPrice.of(TEST_PRICE_VALUE);
15+
16+
public static ProductNew create(final long price) {
17+
return create(TEST_NAME, price);
18+
}
19+
20+
public static ProductNew create(final String name, final long price) {
21+
return ProductNew.newOf(
22+
ProductNameAccessor.create(new Name(name)),
23+
ProductPrice.of(price));
24+
}
1325

1426
private Fixtures() {
1527
throw new UnsupportedOperationException();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package kitchenpos.product.application;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.List;
6+
import kitchenpos.product.Fixtures;
7+
import kitchenpos.product.application.port.in.ProductFindUseCase;
8+
import kitchenpos.product.application.port.out.ProductNewRepository;
9+
import kitchenpos.product.domain.ProductNew;
10+
import kitchenpos.product.fakerepository.ProductNewFakeRepository;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.DisplayNameGeneration;
13+
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
14+
import org.junit.jupiter.api.Test;
15+
import org.junit.jupiter.api.extension.ExtendWith;
16+
import org.mockito.junit.jupiter.MockitoExtension;
17+
18+
@DisplayNameGeneration(ReplaceUnderscores.class)
19+
@ExtendWith(MockitoExtension.class)
20+
class DefaultProductFindUseCaseTest {
21+
22+
private ProductNewRepository repository;
23+
24+
private ProductFindUseCase useCase;
25+
26+
@BeforeEach
27+
void setUp() {
28+
repository = new ProductNewFakeRepository();
29+
30+
useCase = new DefaultProductFindUseCase(repository);
31+
}
32+
33+
@Test
34+
void findAll_저장된_모든_음식_목록을_dto로_변환하여_반환한다() {
35+
36+
// given
37+
final ProductNew product1 = repository.save(Fixtures.create("dummy1", 1_000L));
38+
final ProductNew product2 = repository.save(Fixtures.create("dummy2", 3_000L));
39+
40+
// when
41+
final List<ProductDTO> actual = useCase.findAll();
42+
43+
// then
44+
final ProductDTO expected1 = new ProductDTO(product1);
45+
final ProductDTO expected2 = new ProductDTO(product2);
46+
47+
assertThat(actual)
48+
.usingRecursiveFieldByFieldElementComparator()
49+
.contains(expected1, expected2);
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package kitchenpos.product.application;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
import static org.mockito.ArgumentMatchers.any;
6+
import static org.mockito.Mockito.never;
7+
import static org.mockito.Mockito.verify;
8+
9+
import java.util.UUID;
10+
import kitchenpos.product.Fixtures;
11+
import kitchenpos.product.application.exception.NotExistProductException;
12+
import kitchenpos.product.application.port.in.ProductPriceChangeUseCase;
13+
import kitchenpos.product.application.port.out.ProductNewRepository;
14+
import kitchenpos.product.application.port.out.ProductPriceChangeEventPublisher;
15+
import kitchenpos.product.domain.ProductNew;
16+
import kitchenpos.product.domain.ProductPrice;
17+
import kitchenpos.product.fakerepository.ProductNewFakeRepository;
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.DisplayNameGeneration;
20+
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.extension.ExtendWith;
23+
import org.junit.jupiter.params.ParameterizedTest;
24+
import org.junit.jupiter.params.provider.NullSource;
25+
import org.mockito.Mock;
26+
import org.mockito.junit.jupiter.MockitoExtension;
27+
28+
@DisplayNameGeneration(ReplaceUnderscores.class)
29+
@ExtendWith(MockitoExtension.class)
30+
class DefaultProductPriceChangeUseCaseTest {
31+
32+
@Mock
33+
private ProductPriceChangeEventPublisher mockEventPublisher;
34+
35+
private ProductNewRepository repository;
36+
37+
private ProductPriceChangeUseCase useCase;
38+
39+
@BeforeEach
40+
void setUp() {
41+
repository = new ProductNewFakeRepository();
42+
43+
useCase = new DefaultProductPriceChangeUseCase(repository, mockEventPublisher);
44+
}
45+
46+
47+
@ParameterizedTest
48+
@NullSource
49+
void change_invalid_parameters_id가_null이면_예외를_발생시킨다(final UUID value) {
50+
51+
// when & then
52+
assertThatThrownBy(() -> useCase.change(value, Fixtures.VALID_PRODUCT_PRICE))
53+
.isExactlyInstanceOf(IllegalArgumentException.class);
54+
}
55+
56+
@ParameterizedTest
57+
@NullSource
58+
void change_invalid_parameters_price가_null이면_예외를_발생시킨다(final ProductPrice value) {
59+
60+
// when & then
61+
assertThatThrownBy(() -> useCase.change(UUID.randomUUID(), value))
62+
.isExactlyInstanceOf(IllegalArgumentException.class);
63+
}
64+
65+
@Test
66+
void change_id에_해당하는_음식이_없으면_예외를_발생시킨다() {
67+
68+
// when & then
69+
assertThatThrownBy(() -> useCase.change(UUID.randomUUID(), Fixtures.VALID_PRODUCT_PRICE))
70+
.isExactlyInstanceOf(NotExistProductException.class);
71+
}
72+
73+
@Test
74+
void change_입력받은_가격으로_음식_가격을_변경시킨다() {
75+
// given
76+
final ProductNew product = repository.save(Fixtures.create(5_000L));
77+
78+
// when
79+
useCase.change(product.getId(), ProductPrice.of(10_000L));
80+
81+
// then
82+
assertThat(product.getPrice())
83+
.isEqualTo(ProductPrice.of(10_000L));
84+
}
85+
86+
@Test
87+
void change_가격이_변경되면_가격변경_이벤트를_발행한다() {
88+
// given
89+
final ProductNew product = repository.save(Fixtures.create(5_000L));
90+
91+
// when
92+
useCase.change(product.getId(), ProductPrice.of(10_000L));
93+
94+
// then
95+
verify(mockEventPublisher)
96+
.publish(product.getId());
97+
}
98+
99+
@Test
100+
void change_예외가_발생하면_가격변경_이벤트는_발행되지_않는다() {
101+
// when
102+
throwExceptionScenario();
103+
104+
// then
105+
verify(mockEventPublisher, never())
106+
.publish(any());
107+
}
108+
109+
private void throwExceptionScenario() {
110+
try {
111+
useCase.change(UUID.randomUUID(), Fixtures.VALID_PRODUCT_PRICE);
112+
} catch (final Exception ignored) {
113+
}
114+
}
115+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package kitchenpos.product.application;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
import static org.mockito.Mockito.doReturn;
6+
import static org.mockito.Mockito.doThrow;
7+
8+
import kitchenpos.product.Fixtures;
9+
import kitchenpos.product.application.exception.ContainsProfanityException;
10+
import kitchenpos.product.application.port.in.ProductRegistrationUseCase;
11+
import kitchenpos.product.application.port.out.ProductNewRepository;
12+
import kitchenpos.product.domain.Name;
13+
import kitchenpos.product.domain.ProductNameAccessor;
14+
import kitchenpos.product.domain.ProductNameFactory;
15+
import kitchenpos.product.domain.ProductPrice;
16+
import kitchenpos.product.fakerepository.ProductNewFakeRepository;
17+
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.DisplayNameGeneration;
19+
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.ExtendWith;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.NullSource;
24+
import org.junit.jupiter.params.provider.ValueSource;
25+
import org.mockito.Mock;
26+
import org.mockito.junit.jupiter.MockitoExtension;
27+
28+
@DisplayNameGeneration(ReplaceUnderscores.class)
29+
@ExtendWith(MockitoExtension.class)
30+
class DefaultProductRegistrationUseCaseTest {
31+
32+
@Mock
33+
private ProductNameFactory mockFactory;
34+
35+
private ProductNewRepository repository;
36+
37+
private ProductRegistrationUseCase useCase;
38+
39+
@BeforeEach
40+
void setUp() {
41+
repository = new ProductNewFakeRepository();
42+
43+
useCase = new DefaultProductRegistrationUseCase(mockFactory, repository);
44+
}
45+
46+
@ParameterizedTest
47+
@NullSource
48+
void register_invalid_parameters_음식이름_후보가_null이면_예외를_발생시킨다(final Name value) {
49+
50+
// when & then
51+
assertThatThrownBy(() -> useCase.register(value, Fixtures.VALID_PRODUCT_PRICE))
52+
.isExactlyInstanceOf(IllegalArgumentException.class);
53+
}
54+
55+
@ParameterizedTest
56+
@NullSource
57+
void register_invalid_parameters_음식가격이_null이면_예외를_발생시킨다(final ProductPrice value) {
58+
59+
// when & then
60+
assertThatThrownBy(() -> useCase.register(Fixtures.VALID_NAME, value))
61+
.isExactlyInstanceOf(IllegalArgumentException.class);
62+
}
63+
64+
@ParameterizedTest
65+
@ValueSource(strings = "비속어가포함된이름")
66+
void register_음식이름후보에_비속어가_포함되어_있으면_예외를_발생시킨다(final String value) {
67+
// given
68+
final Name profanityName = new Name(value);
69+
doThrow(ContainsProfanityException.class)
70+
.when(mockFactory)
71+
.create(profanityName);
72+
73+
// when & then
74+
assertThatThrownBy(() -> useCase.register(profanityName, Fixtures.VALID_PRODUCT_PRICE))
75+
.isExactlyInstanceOf(ContainsProfanityException.class);
76+
}
77+
78+
79+
@Test
80+
void register_product를_생성한_후_저장한다() {
81+
// given
82+
doReturn(ProductNameAccessor.create(Fixtures.VALID_NAME))
83+
.when(mockFactory)
84+
.create(Fixtures.VALID_NAME);
85+
86+
// when
87+
final ProductDTO actual = useCase.register(Fixtures.VALID_NAME,
88+
Fixtures.VALID_PRODUCT_PRICE);
89+
90+
// then
91+
assertThat(repository.findById(actual.getId())).isNotNull();
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package kitchenpos.product.domain;
2+
3+
public final class ProductNameAccessor {
4+
5+
public static ProductName create(final Name name) {
6+
return ProductName.of(name);
7+
}
8+
9+
private ProductNameAccessor() {
10+
throw new UnsupportedOperationException();
11+
}
12+
}

0 commit comments

Comments
 (0)