Skip to content

Commit 490b80b

Browse files
authored
test: 테스트 코드 작성 (#78)
* test: 토스 페이먼츠 클라이언트 테스트 추가 (#72) * build: MockWebServer 의존성 추가 * feat: MockHttpServer 헬퍼 클래스 추가 * test: 결제 승인 테스트 코드 작성 * test: 결제 승인 실패 테스트 코드 작성 * test: 테스트 이름 변경 * test: 결제 승인 테스트에서 요청 헤더 검증 로직 추가 * test: 결제 승인 테스트에서 요청 바디 검증 로직 추가 * test: 결제 승인 테스트에서 요청 헤더 검증 로직 추가 * test: 테스트 클래스명 변경 * test: 결제 취소 요청 성공 테스트 코드 작성 * test: 결제 취소 실패 성공 테스트 코드 작성 * test: 테스트 컨테이너 추가 (#75) * build: testContainer 관련 의존성 추가 * test: 테스트 컨테이너 추가 * test: DBInitializer 추가 * test: 결제 API 인수 테스트 성공 케이스 작성 (#76) * feat: UserFixture 추가 * feat: JWT 토큰 발급 메소드 추가 - Jwt 클래스 네이밍 수정 - 테스트 메소드 추가 * fix: MockMvc 접근 제어자 수정 * feat: Cart Fixture 추가 * chore: 코드 포멧팅 * feat: CartMenuItemFixture 추가 * feat: OrderableShopFixture 추가 * feat: OrderableShopMenuFixture 추가 * feat: OrderShopMenuPriceFixture 추가 * feat: 주문가능상점메뉴, 주문가능상점메뉴가격 리파지토리 클래스 추가 * feat: 주문번호 생성 Fake 객체 추가 * feat: 주문번호 생성 Fake 객체 추가 * feat: 장바구니 연간관계 메소드 추가 * test: 임시 배달 결제 정보 저장 API 통합 테스트 작성 * test: 임시 포장 결제 정보 저장 API 통합 테스트 작성 * test: 배달 결제 승인 API 통합 테스트 작성 * test: 포장 결제 승인 API 통합 테스트 작성 * feat: PaymentIdempotencyKeyFixture 추가 * test: 결제 취소 API 통합 테스트 작성 * test: 리파지토리 검증 로직 추가 * test: 결제 API 테스트 클래스 분리 * chore: 코드 포멧팅 * feat: 주문 번호 생성 클래스 MockBean으로 변경 * build: 테스트 application.yml 추가
1 parent b544b93 commit 490b80b

35 files changed

Lines changed: 1691 additions & 28 deletions

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ out/
3636
### VS Code ###
3737
.vscode/
3838

39-
application.yml
39+
**/src/main/resources/application.yml
4040
logs

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ dependencies {
4747

4848
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
4949
testImplementation 'org.springframework.boot:spring-boot-starter-test'
50+
testImplementation 'com.squareup.okhttp3:mockwebserver'
51+
testImplementation 'org.testcontainers:testcontainers:1.19.3'
52+
testImplementation 'org.testcontainers:junit-jupiter:1.19.3'
53+
testImplementation 'org.testcontainers:mysql'
5054
}
5155

5256
clean {

src/main/java/in/koreatech/koin/domain/order/cart/model/Cart.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import java.util.List;
88
import java.util.Optional;
99

10-
import in.koreatech.koin.domain.order.cart.exception.CartAccessDeniedException;
10+
import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenu;
11+
import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuOption;
12+
import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice;
1113
import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop;
1214
import in.koreatech.koin.domain.user.model.User;
1315
import in.koreatech.payment.common.model.BaseEntity;
@@ -22,6 +24,7 @@
2224
import jakarta.persistence.OneToMany;
2325
import jakarta.persistence.OneToOne;
2426
import jakarta.persistence.Table;
27+
import lombok.Builder;
2528
import lombok.Getter;
2629
import lombok.NoArgsConstructor;
2730

@@ -47,9 +50,45 @@ public class Cart extends BaseEntity {
4750
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true)
4851
List<CartMenuItem> cartMenuItems = new ArrayList<>();
4952

53+
@Builder
54+
private Cart(
55+
User user,
56+
OrderableShop orderableShop
57+
) {
58+
this.user = user;
59+
this.orderableShop = orderableShop;
60+
}
61+
5062
public Integer calculateItemsAmount() {
5163
return this.cartMenuItems.stream()
5264
.mapToInt(CartMenuItem::calculateTotalAmount)
5365
.sum();
5466
}
67+
68+
// TODO. 코인 서버와 동일 로직으로 변경
69+
public void addItem(OrderableShopMenu menu, OrderableShopMenuPrice price, List<OrderableShopMenuOption> options,
70+
Integer quantity) {
71+
// 장바구니에 옵션 까지 전부 동일한 메뉴가 이미 존재 하는 경우, 담긴 상품 수량 증가
72+
Optional<CartMenuItem> existingItem = findSameItem(menu, price, options);
73+
74+
if (existingItem.isPresent()) {
75+
existingItem.get().increaseQuantity(quantity);
76+
} else {
77+
this.cartMenuItems.add(CartMenuItem.builder()
78+
.cart(this)
79+
.orderableShopMenu(menu)
80+
.orderableShopMenuPrice(price)
81+
.quantity(quantity)
82+
.isModified(false)
83+
.build()
84+
);
85+
}
86+
}
87+
88+
private Optional<CartMenuItem> findSameItem(OrderableShopMenu menu, OrderableShopMenuPrice price,
89+
List<OrderableShopMenuOption> options) {
90+
return this.cartMenuItems.stream()
91+
.filter(item -> item.isSameItem(menu, price, options))
92+
.findFirst();
93+
}
5594
}

src/main/java/in/koreatech/koin/domain/order/cart/model/CartMenuItem.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.List;
88

99
import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenu;
10+
import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuOption;
1011
import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice;
1112
import in.koreatech.payment.common.model.BaseEntity;
1213
import jakarta.persistence.CascadeType;
@@ -55,11 +56,55 @@ public class CartMenuItem extends BaseEntity {
5556
@OneToMany(mappedBy = "cartMenuItem", cascade = CascadeType.ALL, orphanRemoval = true)
5657
private List<CartMenuItemOption> cartMenuItemOptions = new ArrayList<>();
5758

59+
@Builder
60+
private CartMenuItem(
61+
Cart cart,
62+
OrderableShopMenu orderableShopMenu,
63+
OrderableShopMenuPrice orderableShopMenuPrice,
64+
Integer quantity,
65+
Boolean isModified
66+
) {
67+
this.cart = cart;
68+
this.orderableShopMenu = orderableShopMenu;
69+
this.orderableShopMenuPrice = orderableShopMenuPrice;
70+
this.quantity = quantity;
71+
this.isModified = isModified;
72+
}
73+
5874
public Integer calculateTotalAmount() {
5975
int totalOptionPrice = this.cartMenuItemOptions.stream()
6076
.mapToInt(CartMenuItemOption::getOptionPrice)
6177
.sum();
6278

6379
return (this.orderableShopMenuPrice.getPrice() + totalOptionPrice) * this.quantity;
6480
}
81+
82+
public void increaseQuantity(Integer amount) {
83+
this.quantity += amount;
84+
}
85+
86+
public boolean isSameItem(OrderableShopMenu menu, OrderableShopMenuPrice price, List<OrderableShopMenuOption> options) {
87+
// 메뉴와 가격 ID가 다른 경우
88+
if (!this.orderableShopMenu.getId().equals(menu.getId()) || !this.orderableShopMenuPrice.getId().equals(price.getId())) {
89+
return false;
90+
}
91+
92+
// 선택한 옵션의 개수가 다른 경우
93+
if (this.cartMenuItemOptions.size() != options.size()) {
94+
return false;
95+
}
96+
97+
// 선택한 옵션의 구성이 다른 경우 (정렬 후 비교)
98+
List<Integer> existingOptionIds = this.cartMenuItemOptions.stream()
99+
.map(opt -> opt.getOrderableShopMenuOption().getId())
100+
.sorted()
101+
.toList();
102+
103+
List<Integer> newOptionIds = options.stream()
104+
.map(OrderableShopMenuOption::getId)
105+
.sorted()
106+
.toList();
107+
108+
return existingOptionIds.equals(newOptionIds);
109+
}
65110
}

src/main/java/in/koreatech/koin/domain/order/cart/repository/CartRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ default Cart getCartByUserId(Integer userId) {
2020
}
2121

2222
void deleteByUserId(Integer userId);
23+
24+
Cart save(Cart cart);
2325
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package in.koreatech.koin.domain.order.repository;
22

3+
import java.util.List;
4+
35
import org.springframework.data.repository.Repository;
46

57
import in.koreatech.koin.domain.order.model.PaymentCancel;
68

79
public interface PaymentCancelRepository extends Repository<PaymentCancel, Integer> {
810

911
void saveAll(Iterable<PaymentCancel> paymentCancels);
12+
13+
List<PaymentCancel> findAllByPaymentId(Integer paymentId);
1014
}

src/main/java/in/koreatech/koin/domain/order/shop/model/entity/menu/OrderableShopMenu.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,25 @@ public class OrderableShopMenu extends BaseEntity {
6464

6565
@OneToMany(mappedBy = "menu", cascade = CascadeType.ALL, orphanRemoval = true)
6666
private List<OrderableShopMenuImage> menuImages = new ArrayList<>();
67+
68+
@Builder
69+
private OrderableShopMenu(
70+
OrderableShop orderableShop,
71+
String name,
72+
String description,
73+
Boolean isSoldOut,
74+
Boolean isDeleted,
75+
List<OrderableShopMenuOptionGroupMap> menuOptionGroupMap,
76+
List<OrderableShopMenuPrice> menuPrices,
77+
List<OrderableShopMenuImage> menuImages
78+
) {
79+
this.orderableShop = orderableShop;
80+
this.name = name;
81+
this.description = description;
82+
this.isSoldOut = isSoldOut;
83+
this.isDeleted = isDeleted;
84+
this.menuOptionGroupMap = menuOptionGroupMap;
85+
this.menuPrices = menuPrices;
86+
this.menuImages = menuImages;
87+
}
6788
}

src/main/java/in/koreatech/koin/domain/order/shop/model/entity/menu/OrderableShopMenuPrice.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import jakarta.persistence.JoinColumn;
1515
import jakarta.persistence.ManyToOne;
1616
import jakarta.persistence.Table;
17+
import lombok.Builder;
1718
import lombok.Getter;
1819
import lombok.NoArgsConstructor;
1920

@@ -41,4 +42,17 @@ public class OrderableShopMenuPrice extends BaseEntity {
4142

4243
@Column(name = "is_deleted", nullable = false)
4344
private Boolean isDeleted = false;
45+
46+
@Builder
47+
private OrderableShopMenuPrice(
48+
OrderableShopMenu menu,
49+
String name,
50+
Integer price,
51+
Boolean isDeleted
52+
) {
53+
this.menu = menu;
54+
this.name = name;
55+
this.price = price;
56+
this.isDeleted = isDeleted;
57+
}
4458
}

src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,23 @@ public class OrderableShop extends BaseEntity {
6464
public Integer calculateDeliveryFee(Integer orderAmount) {
6565
return this.shop.getBaseDeliveryTips().calculateDeliveryTip(orderAmount);
6666
}
67+
68+
@Builder
69+
private OrderableShop(
70+
Shop shop,
71+
boolean delivery,
72+
boolean takeout,
73+
boolean serviceEvent,
74+
Integer minimumOrderAmount,
75+
boolean isDeleted,
76+
List<OrderableShopMenuGroup> menuGroups
77+
) {
78+
this.shop = shop;
79+
this.delivery = delivery;
80+
this.takeout = takeout;
81+
this.serviceEvent = serviceEvent;
82+
this.minimumOrderAmount = minimumOrderAmount;
83+
this.isDeleted = isDeleted;
84+
this.menuGroups = menuGroups;
85+
}
6786
}

src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/ShopOperation.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import jakarta.persistence.JoinColumn;
1515
import jakarta.persistence.OneToOne;
1616
import jakarta.persistence.Table;
17+
import lombok.Builder;
1718
import lombok.Getter;
1819
import lombok.NoArgsConstructor;
1920

@@ -38,4 +39,15 @@ public class ShopOperation {
3839

3940
@Column(name = "is_deleted", nullable = false)
4041
private boolean isDeleted = false;
42+
43+
@Builder
44+
private ShopOperation(
45+
Shop shop,
46+
boolean isOpen,
47+
boolean isDeleted
48+
) {
49+
this.shop = shop;
50+
this.isOpen = isOpen;
51+
this.isDeleted = isDeleted;
52+
}
4153
}

0 commit comments

Comments
 (0)