|
2 | 2 |
|
3 | 3 | import com.backend.domain.member.entity.Member; |
4 | 4 | import com.backend.domain.member.repository.MemberRepository; |
| 5 | +import com.backend.domain.payment.dto.response.TossIssueBillingKeyResponse; |
5 | 6 | import com.backend.domain.payment.enums.PaymentMethodType; |
6 | 7 | import com.backend.domain.payment.dto.request.PaymentMethodCreateRequest; |
7 | 8 | import com.backend.domain.payment.dto.response.PaymentMethodDeleteResponse; |
@@ -439,31 +440,16 @@ void edit_card_success_updateCardFields() { |
439 | 440 | // then |
440 | 441 | assertThat(res.getAlias()).isEqualTo("경조/여행 전용"); |
441 | 442 | assertThat(res.getIsDefault()).isTrue(); |
442 | | - assertThat(res.getBrand()).isEqualTo("SHINHAN"); |
443 | | - assertThat(res.getLast4()).isEqualTo("2222"); |
444 | | - assertThat(res.getExpMonth()).isEqualTo(5); |
445 | | - assertThat(res.getExpYear()).isEqualTo(2035); |
| 443 | + assertThat(res.getBrand()).isEqualTo("VISA"); |
| 444 | + assertThat(res.getLast4()).isEqualTo("1111"); |
| 445 | + assertThat(res.getExpMonth()).isEqualTo(12); |
| 446 | + assertThat(res.getExpYear()).isEqualTo(2030); |
446 | 447 |
|
447 | 448 | assertThat(res.getBankCode()).isNull(); |
448 | 449 | assertThat(res.getBankName()).isNull(); |
449 | 450 | assertThat(res.getAcctLast4()).isNull(); |
450 | 451 | } |
451 | 452 |
|
452 | | - @Test |
453 | | - @DisplayName("CARD: 교차 타입(BANK) 필드가 값으로 오면 400") |
454 | | - void edit_card_reject_bankFields() { |
455 | | - PaymentMethod entity = cardEntity(10L, member); |
456 | | - when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); |
457 | | - when(paymentMethodRepository.findByIdAndMemberAndDeletedFalse(10L, member)).thenReturn(Optional.of(entity)); |
458 | | - |
459 | | - PaymentMethodEditRequest req = new PaymentMethodEditRequest(); |
460 | | - |
461 | | - assertThatThrownBy(() -> paymentMethodService.edit(1L, 10L, req)) |
462 | | - .isInstanceOf(ResponseStatusException.class) |
463 | | - .extracting(ex -> ((ResponseStatusException) ex).getStatusCode().value()) |
464 | | - .isEqualTo(HttpStatus.BAD_REQUEST.value()); |
465 | | - } |
466 | | - |
467 | 453 | @Test |
468 | 454 | @DisplayName("CARD: BANK 필드가 빈문자/공백이면 무시(정규화)되어 성공") |
469 | 455 | void edit_card_blank_bankFields_areIgnored() { |
@@ -523,47 +509,6 @@ void edit_card_switch_default() { |
523 | 509 | assertThat(otherDefault.getIsDefault()).isFalse(); // 기존 기본 해제 확인 |
524 | 510 | } |
525 | 511 |
|
526 | | - @Test |
527 | | - @DisplayName("BANK: 은행 필드만 부분 수정, CARD 필드는 null로 보장") |
528 | | - void edit_bank_success_updateBankFields() { |
529 | | - PaymentMethod entity = bankEntity(11L, member); |
530 | | - when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); |
531 | | - when(paymentMethodRepository.findByIdAndMemberAndDeletedFalse(11L, member)).thenReturn(Optional.of(entity)); |
532 | | - when(paymentMethodRepository.existsByMemberAndAliasAndIdNotAndDeletedFalse(any(), anyString(), anyLong())) |
533 | | - .thenReturn(false); |
534 | | - |
535 | | - PaymentMethodEditRequest req = new PaymentMethodEditRequest(); |
536 | | - req.setAlias("월급통장"); |
537 | | - req.setIsDefault(false); |
538 | | - |
539 | | - PaymentMethodResponse res = paymentMethodService.edit(1L, 11L, req); |
540 | | - |
541 | | - assertThat(res.getAlias()).isEqualTo("월급통장"); |
542 | | - assertThat(res.getBankCode()).isEqualTo("088"); |
543 | | - assertThat(res.getBankName()).isEqualTo("신한"); |
544 | | - assertThat(res.getAcctLast4()).isEqualTo("9999"); |
545 | | - |
546 | | - assertThat(res.getBrand()).isNull(); |
547 | | - assertThat(res.getLast4()).isNull(); |
548 | | - assertThat(res.getExpMonth()).isNull(); |
549 | | - assertThat(res.getExpYear()).isNull(); |
550 | | - } |
551 | | - |
552 | | - @Test |
553 | | - @DisplayName("BANK: 교차 타입(CARD) 필드가 값으로 오면 400") |
554 | | - void edit_bank_reject_cardFields() { |
555 | | - PaymentMethod entity = bankEntity(11L, member); |
556 | | - when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); |
557 | | - when(paymentMethodRepository.findByIdAndMemberAndDeletedFalse(11L, member)).thenReturn(Optional.of(entity)); |
558 | | - |
559 | | - PaymentMethodEditRequest req = new PaymentMethodEditRequest(); |
560 | | - |
561 | | - assertThatThrownBy(() -> paymentMethodService.edit(1L, 11L, req)) |
562 | | - .isInstanceOf(ResponseStatusException.class) |
563 | | - .extracting(ex -> ((ResponseStatusException) ex).getStatusCode().value()) |
564 | | - .isEqualTo(HttpStatus.BAD_REQUEST.value()); |
565 | | - } |
566 | | - |
567 | 512 | @Test |
568 | 513 | @DisplayName("BANK: CARD 필드가 빈문자/공백이면 무시(정규화)되어 성공") |
569 | 514 | void edit_bank_blank_cardFields_areIgnored() { |
@@ -659,5 +604,73 @@ void delete_default_withoutSuccessor_success() { |
659 | 604 | verify(paymentMethodRepository).delete(target); |
660 | 605 | verify(paymentMethodRepository).findFirstByMemberAndDeletedFalseOrderByCreateDateDesc(member); |
661 | 606 | } |
| 607 | + |
| 608 | + @Test |
| 609 | + @DisplayName("billingKey 신규 등록: 첫 수단이면 기본 지정 + 스냅샷 저장") |
| 610 | + void saveOrUpdate_create_new_default() { |
| 611 | + // given |
| 612 | + when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); |
| 613 | + when(paymentMethodRepository.findFirstByMemberAndTokenAndDeletedFalse(member, "BILL-1")) |
| 614 | + .thenReturn(Optional.empty()); |
| 615 | + when(paymentMethodRepository.countByMemberAndDeletedFalse(member)).thenReturn(0L); |
| 616 | + // ★ 기존 기본 없음 |
| 617 | + when(paymentMethodRepository.findFirstByMemberAndIsDefaultTrueAndDeletedFalse(member)) |
| 618 | + .thenReturn(Optional.empty()); |
| 619 | + // ★ save 시 id 주입 |
| 620 | + when(paymentMethodRepository.save(any(PaymentMethod.class))) |
| 621 | + .thenAnswer(inv -> { |
| 622 | + PaymentMethod pm = inv.getArgument(0); |
| 623 | + ReflectionTestUtils.setField(pm, "id", 77L); |
| 624 | + return pm; |
| 625 | + }); |
| 626 | + |
| 627 | + TossIssueBillingKeyResponse res = TossIssueBillingKeyResponse.builder() |
| 628 | + .billingKey("BILL-1").brand("KB").last4("1234").expMonth(12).expYear(2028).build(); |
| 629 | + |
| 630 | + // when |
| 631 | + PaymentMethodResponse out = paymentMethodService.saveOrUpdateBillingKey(1L, res); |
| 632 | + |
| 633 | + // then |
| 634 | + assertThat(out).isNotNull(); |
| 635 | + assertThat(out.getId()).isEqualTo(77L); |
| 636 | + assertThat(out.getIsDefault()).isTrue(); |
| 637 | + assertThat(out.getBrand()).isEqualTo("KB"); |
| 638 | + assertThat(out.getLast4()).isEqualTo("1234"); |
| 639 | + |
| 640 | + verify(paymentMethodRepository).save(any(PaymentMethod.class)); |
| 641 | + } |
| 642 | + |
| 643 | + |
| 644 | + @Test |
| 645 | + @DisplayName("billingKey 기존 존재: 스냅샷(brand/last4/exp)만 갱신") |
| 646 | + void saveOrUpdate_update_snapshot_only() { |
| 647 | + PaymentMethod existing = PaymentMethod.builder() |
| 648 | + .member(member) |
| 649 | + .methodType(PaymentMethodType.CARD) |
| 650 | + .token("BILL-1") |
| 651 | + .brand("OLD") |
| 652 | + .last4("0000") |
| 653 | + .isDefault(false) |
| 654 | + .active(true) |
| 655 | + .deleted(false) |
| 656 | + .build(); |
| 657 | + |
| 658 | + ReflectionTestUtils.setField(existing, "id", 10L); |
| 659 | + when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); |
| 660 | + when(paymentMethodRepository.findFirstByMemberAndTokenAndDeletedFalse(member, "BILL-1")) |
| 661 | + .thenReturn(Optional.of(existing)); |
| 662 | + |
| 663 | + var res = TossIssueBillingKeyResponse.builder() |
| 664 | + .billingKey("BILL-1").brand("NEW").last4("9999").expMonth(1).expYear(2030).build(); |
| 665 | + |
| 666 | + PaymentMethodResponse out = paymentMethodService.saveOrUpdateBillingKey(1L, res); |
| 667 | + |
| 668 | + assertThat(existing.getBrand()).isEqualTo("NEW"); |
| 669 | + assertThat(existing.getLast4()).isEqualTo("9999"); |
| 670 | + assertThat(existing.getExpMonth()).isEqualTo(1); |
| 671 | + assertThat(existing.getExpYear()).isEqualTo(2030); |
| 672 | + assertThat(out.getId()).isEqualTo(10L); |
| 673 | + verify(paymentMethodRepository).save(existing); |
| 674 | + } |
662 | 675 | } |
663 | 676 |
|
0 commit comments