From 03f496f34fabf05ac0089a8fe40ddab463bfc59a Mon Sep 17 00:00:00 2001 From: seungh1024 Date: Mon, 4 Mar 2024 20:07:25 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=B6=A9=EC=A0=84=20=ED=95=9C?= =?UTF-8?q?=EB=8F=84=20=EA=B4=80=EB=A6=AC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 일일 충전 한도를 별도의 테이블이 아닌 메인 계좌에서 함께 관리합니다. - 기존은 별도의 테이블로 분리하여 매일 초기화를 했지만 더 좋은 방법이 생각나 변경했습니다. - 굳이 매일 변경할 필요가 없이, 최근 업데이트 날짜와 오늘 날짜가 다르다면 한도를 초기화하고 남은 로직을 이어서 실행합니다. --- .../bankaccount/cache/AccountCacheConfig.java | 19 ----- .../controller/MainAccountController.java | 7 +- .../dto/response/MainAccountResponseDto.java | 5 +- .../bankaccount/entity/ChargeLimit.java | 63 -------------- .../bankaccount/entity/MainAccount.java | 37 +++++++-- .../exception/AccountErrorCode.java | 3 +- .../repository/ChargeLimitRepository.java | 27 ------ .../scheduler/ChargeLimitScheduler.java | 26 ------ .../service/MainAccountService.java | 42 ++++------ .../assignment/common/entity/BaseEntity.java | 4 + .../member/dto/request/SignUpRequestDto.java | 3 +- .../assignment/member/entity/Member.java | 7 +- .../member/service/MemberService.java | 11 +-- .../member/session/SessionMemberInfo.java | 3 +- src/main/resources/application.yml | 6 -- .../concurrency/MoneySendConcurrencyTest.java | 60 ++------------ .../controller/MainAccountControllerTest.java | 9 +- .../SavingAccountControllerTest.java | 2 +- .../service/MainAccountServiceTest.java | 82 ++++++------------- .../controller/MemberControllerTest.java | 4 +- .../member/service/MemberServiceImplTest.java | 6 -- 21 files changed, 109 insertions(+), 317 deletions(-) delete mode 100644 src/main/java/org/c4marathon/assignment/bankaccount/entity/ChargeLimit.java delete mode 100644 src/main/java/org/c4marathon/assignment/bankaccount/repository/ChargeLimitRepository.java delete mode 100644 src/main/java/org/c4marathon/assignment/bankaccount/scheduler/ChargeLimitScheduler.java diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/cache/AccountCacheConfig.java b/src/main/java/org/c4marathon/assignment/bankaccount/cache/AccountCacheConfig.java index d9d3e323e..d2c700d3d 100644 --- a/src/main/java/org/c4marathon/assignment/bankaccount/cache/AccountCacheConfig.java +++ b/src/main/java/org/c4marathon/assignment/bankaccount/cache/AccountCacheConfig.java @@ -5,9 +5,6 @@ import org.springframework.cache.concurrent.ConcurrentMapCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericToStringSerializer; @Configuration @EnableCaching @@ -17,20 +14,4 @@ public class AccountCacheConfig { public CacheManager savingProductCacheManager() { return new ConcurrentMapCacheManager("savingProduct"); } - - /** - * - * DB에 저장된 일일 충전한도 값을 한 번 읽으면 Redis에 저장하여 관리합니다. - * DB에 별도의 테이블로 관리하면 디스크 공간과 인덱스를 위한 메모리 공간이 사용됩니다. - * 그렇게 하기 보다는 Redis에서 로 관리하여 인덱스 테이블과 비슷한 메모리만 사용하고자 했습니다. - */ - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - final RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - template.setKeySerializer(new GenericToStringSerializer<>(Long.class)); - template.setValueSerializer(new GenericToStringSerializer<>(Long.class)); - - return template; - } } diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/controller/MainAccountController.java b/src/main/java/org/c4marathon/assignment/bankaccount/controller/MainAccountController.java index 05bcaedc3..47dd22971 100644 --- a/src/main/java/org/c4marathon/assignment/bankaccount/controller/MainAccountController.java +++ b/src/main/java/org/c4marathon/assignment/bankaccount/controller/MainAccountController.java @@ -30,8 +30,7 @@ public class MainAccountController { @PostMapping("/charge") public long chargeMoney(@Login SessionMemberInfo memberInfo, @Valid @RequestBody ChargeMoneyRequestDto requestDto) { - return mainAccountService.chargeMoney(memberInfo.mainAccountPk(), requestDto.money(), - memberInfo.chargeLimitPk()); + return mainAccountService.chargeMoney(memberInfo.mainAccountPk(), requestDto.money()); } @ResponseStatus(HttpStatus.OK) @@ -39,7 +38,7 @@ public long chargeMoney(@Login SessionMemberInfo memberInfo, public void sendToSavingAccount(@Login SessionMemberInfo memberInfo, @Valid @RequestBody SendMoneyRequestDto sendAccountInfo) { mainAccountService.sendToSavingAccount(memberInfo.mainAccountPk(), sendAccountInfo.accountPk(), - sendAccountInfo.money(), memberInfo.chargeLimitPk()); + sendAccountInfo.money()); } @ResponseStatus(HttpStatus.OK) @@ -53,6 +52,6 @@ public MainAccountResponseDto getMainAccountInfo(@Login SessionMemberInfo member public void sendToOtherAccount(@Login SessionMemberInfo memberInfo, @Valid @RequestBody SendMoneyRequestDto sendAccountInfo) { mainAccountService.sendToOtherAccount(memberInfo.mainAccountPk(), sendAccountInfo.accountPk(), - sendAccountInfo.money(), memberInfo.chargeLimitPk()); + sendAccountInfo.money()); } } diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/dto/response/MainAccountResponseDto.java b/src/main/java/org/c4marathon/assignment/bankaccount/dto/response/MainAccountResponseDto.java index 9e02670a5..3cfbc7030 100644 --- a/src/main/java/org/c4marathon/assignment/bankaccount/dto/response/MainAccountResponseDto.java +++ b/src/main/java/org/c4marathon/assignment/bankaccount/dto/response/MainAccountResponseDto.java @@ -4,9 +4,12 @@ public record MainAccountResponseDto( long accountPk, + long chargeLimit, + long spareMoney, long money ) { public MainAccountResponseDto(MainAccount mainAccount) { - this(mainAccount.getAccountPk(), mainAccount.getMoney()); + this(mainAccount.getAccountPk(), mainAccount.getChargeLimit(), mainAccount.getSpareMoney(), + mainAccount.getMoney()); } } diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/entity/ChargeLimit.java b/src/main/java/org/c4marathon/assignment/bankaccount/entity/ChargeLimit.java deleted file mode 100644 index 7f02dc7fc..000000000 --- a/src/main/java/org/c4marathon/assignment/bankaccount/entity/ChargeLimit.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.c4marathon.assignment.bankaccount.entity; - -import org.c4marathon.assignment.common.utils.ConstValue; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Index; -import jakarta.persistence.Table; -import lombok.Getter; - -/** - * - * 생성 시간, 업데이트 시간은 뺐습니다. 이 데이터로 딱히 뭔가를 할 것 같다고 생각이 들지 않았기 때문입니다. - * step 1의 코드 리뷰를 통해 캐시를 글로벌로 써야겠다!라는 생각에 레디스를 사용했지만, 00시에 초기화 하는 곳에서 문제가 발생했습니다. - * 전체 삭제하는 메소드가 O(N)의 시간이 걸려서 RedisTemplate에서 deprecated 되었기 때문입니다. - * 그러다 특강에서 더 자세한 이유를 듣게 되었고 캐싱하는 집착?을 포기하고 데이터베이스에 관리하기로 결정했습니다. - * - * MainAccount와 같은 테이블에서 데이터를 관리하는 방법도 생각해 보았습니다. - * 하지만 이 방법의 경우 00시에 충전 한도를 일괄 업데이트를 하면 MainAccount의 모든 레코드에 락이 걸릴 것입니다. - * 페이 서비스 특성 상 은행의 점검 시간 때문에 충전은 안되어도 현재 잔고에서 이체나 구매 등은 자유롭게 됩니다. - * 그렇기에 별도로 분리해서 ChargeLimit 테이블만 전체 업데이트를 하고 MainAccount에서의 작업은 가능하도록 별도의 테이블로 분리했습니다. - * - * Member - MainAccount 처럼 둘 다 조회를 하는 경우가 많기에 Member와 관계를 맺지 않고, chargeLimit의 pk를 Member가 관리하는 방법을 사용했습니다. - */ -@Entity -@Getter -@Table(indexes = {@Index(name = "check_index", columnList = "charge_check")}) -public class ChargeLimit { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "limit_pk", nullable = false, updatable = false) - private long limitPk; - - // 최대 충전 한도 - @Column(name = "limit_money", nullable = false) - private long limitMoney; - - // 추가로 충전할 수 있는 금액 - @Column(name = "spare_money", nullable = false) - private long spareMoney; - - // 오늘 충전 여부 - @Column(name = "charge_check", nullable = false) - private boolean chargeCheck; - - public ChargeLimit() { - this.limitMoney = ConstValue.LimitConst.CHARGE_LIMIT; - this.spareMoney = ConstValue.LimitConst.CHARGE_LIMIT; - this.chargeCheck = false; - } - - public boolean charge(long money) { - if (spareMoney >= money) { - spareMoney -= money; - this.chargeCheck = true; - return true; - } - return false; - } -} diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/entity/MainAccount.java b/src/main/java/org/c4marathon/assignment/bankaccount/entity/MainAccount.java index c80978ce3..04ffecd1c 100644 --- a/src/main/java/org/c4marathon/assignment/bankaccount/entity/MainAccount.java +++ b/src/main/java/org/c4marathon/assignment/bankaccount/entity/MainAccount.java @@ -1,6 +1,9 @@ package org.c4marathon.assignment.bankaccount.entity; +import java.time.LocalDateTime; + import org.c4marathon.assignment.common.entity.BaseEntity; +import org.c4marathon.assignment.common.utils.ConstValue; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -25,19 +28,41 @@ public class MainAccount extends BaseEntity { @Column(name = "money", nullable = false) private long money; + // 최대 충전 한도 + @Column(name = "charge_money", nullable = false) + private long chargeLimit; + + // 추가로 충전할 수 있는 금액 + @Column(name = "spare_money", nullable = false) + private long spareMoney; + public MainAccount() { this.money = 0L; + this.chargeLimit = ConstValue.LimitConst.CHARGE_LIMIT; + this.spareMoney = ConstValue.LimitConst.CHARGE_LIMIT; } - public MainAccount(long money) { - this.money = money; + public void minusMoney(long money) { + this.money -= money; } - public void chargeMoney(long money) { - this.money += money; + public void chargeCheck() { + int lastDay = this.getUpdatedAt().getDayOfMonth(); + LocalDateTime now = LocalDateTime.now(); + int nowDay = now.getDayOfMonth(); + if (lastDay != nowDay) { + this.setUpdatedAt(now); + this.chargeLimit = ConstValue.LimitConst.CHARGE_LIMIT; + this.spareMoney = ConstValue.LimitConst.CHARGE_LIMIT; + } } - public void minusMoney(long money) { - this.money -= money; + public boolean charge(long money) { + if (this.spareMoney >= money) { + this.spareMoney -= money; + this.money += money; + return true; + } + return false; } } diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/exception/AccountErrorCode.java b/src/main/java/org/c4marathon/assignment/bankaccount/exception/AccountErrorCode.java index 3825e17d4..48f6d2460 100644 --- a/src/main/java/org/c4marathon/assignment/bankaccount/exception/AccountErrorCode.java +++ b/src/main/java/org/c4marathon/assignment/bankaccount/exception/AccountErrorCode.java @@ -12,8 +12,7 @@ public enum AccountErrorCode implements ErrorCode { CHARGE_LIMIT_EXCESS(HttpStatus.BAD_REQUEST, "일일 충전 한도를 초과했습니다."), ACCOUNT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 계좌입니다."), PRODUCT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 적금 상품입니다."), - INVALID_MONEY_SEND(HttpStatus.BAD_REQUEST, "잔고가 부족합니다."), - CHARGE_LIMIT_NOT_FOUND(HttpStatus.NOT_FOUND, "충전 한도 정보를 찾을 수 없습니다."); + INVALID_MONEY_SEND(HttpStatus.BAD_REQUEST, "잔고가 부족합니다."); private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/repository/ChargeLimitRepository.java b/src/main/java/org/c4marathon/assignment/bankaccount/repository/ChargeLimitRepository.java deleted file mode 100644 index 3a4746ece..000000000 --- a/src/main/java/org/c4marathon/assignment/bankaccount/repository/ChargeLimitRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.c4marathon.assignment.bankaccount.repository; - -import java.util.Optional; - -import org.c4marathon.assignment.bankaccount.entity.ChargeLimit; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Lock; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import jakarta.persistence.LockModeType; - -public interface ChargeLimitRepository extends JpaRepository { - @Modifying - @Query(""" - update ChargeLimit cl - set cl.spareMoney = cl.limitMoney, - cl.chargeCheck = false - where cl.chargeCheck = true - """) - void bulkSpareMoneyInit(); - - @Lock(LockModeType.PESSIMISTIC_WRITE) - @Query("select cl from ChargeLimit cl where cl.limitPk = :limitPk") - Optional findByPkForUpdate(@Param("limitPk") long limitPk); -} diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/scheduler/ChargeLimitScheduler.java b/src/main/java/org/c4marathon/assignment/bankaccount/scheduler/ChargeLimitScheduler.java deleted file mode 100644 index 888fa49a7..000000000 --- a/src/main/java/org/c4marathon/assignment/bankaccount/scheduler/ChargeLimitScheduler.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.c4marathon.assignment.bankaccount.scheduler; - -import org.c4marathon.assignment.bankaccount.repository.ChargeLimitRepository; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; - -import lombok.RequiredArgsConstructor; - -@Component -@RequiredArgsConstructor -public class ChargeLimitScheduler { - private final ChargeLimitRepository chargeLimitRepository; - - /** - * - * 충전 한도를 00시에 초기화 해주는 스케줄러 - * ChargeLimit 테이블 sapreMoney 값을 CHARGE_LIMIT으로 초기화한다. - */ - @Scheduled(cron = "0 0 0 * * *") - @Transactional(isolation = Isolation.READ_COMMITTED) - public void chargeLimitSchedule() { - chargeLimitRepository.bulkSpareMoneyInit(); - } -} diff --git a/src/main/java/org/c4marathon/assignment/bankaccount/service/MainAccountService.java b/src/main/java/org/c4marathon/assignment/bankaccount/service/MainAccountService.java index 08fac29b1..166ab02f6 100644 --- a/src/main/java/org/c4marathon/assignment/bankaccount/service/MainAccountService.java +++ b/src/main/java/org/c4marathon/assignment/bankaccount/service/MainAccountService.java @@ -1,12 +1,10 @@ package org.c4marathon.assignment.bankaccount.service; import org.c4marathon.assignment.bankaccount.dto.response.MainAccountResponseDto; -import org.c4marathon.assignment.bankaccount.entity.ChargeLimit; import org.c4marathon.assignment.bankaccount.entity.MainAccount; import org.c4marathon.assignment.bankaccount.entity.SavingAccount; import org.c4marathon.assignment.bankaccount.entity.SendRecord; import org.c4marathon.assignment.bankaccount.exception.AccountErrorCode; -import org.c4marathon.assignment.bankaccount.repository.ChargeLimitRepository; import org.c4marathon.assignment.bankaccount.repository.MainAccountRepository; import org.c4marathon.assignment.bankaccount.repository.SavingAccountRepository; import org.c4marathon.assignment.bankaccount.repository.SendRecordRepository; @@ -25,7 +23,6 @@ public class MainAccountService { private final SavingAccountRepository savingAccountRepository; private final DepositHandlerService depositHandlerService; private final SendRecordRepository sendRecordRepository; - private final ChargeLimitRepository chargeLimitRepository; /** * @@ -36,24 +33,21 @@ public class MainAccountService { * ChargeLimitManager를 통해 충전이 가능한지 확인하고 money만큼 충전 후 계좌 잔고를 리턴합니다. */ @Transactional(isolation = Isolation.READ_COMMITTED) - public long chargeMoney(long mainAccountPk, long money, long chargeLimitPk) { - checkAndCharge(money, chargeLimitPk); - + public long chargeMoney(long mainAccountPk, long money) { MainAccount mainAccount = mainAccountRepository.findByPkForUpdate(mainAccountPk) .orElseThrow(() -> AccountErrorCode.ACCOUNT_NOT_FOUND.accountException()); - - mainAccount.chargeMoney(money); + checkAndCharge(money, mainAccount); mainAccountRepository.save(mainAccount); return mainAccount.getMoney(); } @Transactional(isolation = Isolation.READ_COMMITTED) - public void sendToSavingAccount(long mainAccountPk, long savingAccountPk, long money, long chargeLimitPk) { + public void sendToSavingAccount(long mainAccountPk, long savingAccountPk, long money) { MainAccount mainAccount = mainAccountRepository.findByPkForUpdate(mainAccountPk) .orElseThrow(AccountErrorCode.ACCOUNT_NOT_FOUND::accountException); - autoMoneyChange(mainAccount, money, chargeLimitPk); + autoMoneyChange(mainAccount, money); SavingAccount savingAccount = savingAccountRepository.findByPkForUpdate(savingAccountPk) .orElseThrow(AccountErrorCode.ACCOUNT_NOT_FOUND::accountException); @@ -86,12 +80,12 @@ public MainAccountResponseDto getMainAccountInfo(long mainAccountPk) { * 그래서 현재의 이체 로그를 이후 step에서 구현할 로그로 사용하지 않는다면, A->B의 이체 로직을 한 번에 묶은 것과 큰 성능 차이가 없는 것 아닌가?라는 의문이 들었습니다. * */ @Transactional(isolation = Isolation.READ_COMMITTED) - public void sendToOtherAccount(long senderPk, long depositPk, long money, long chargeLimitPk) { + public void sendToOtherAccount(long senderPk, long depositPk, long money) { // 1. 나의 계좌에서 이체할 금액을 빼준다. MainAccount myAccount = mainAccountRepository.findByPkForUpdate(senderPk) .orElseThrow(AccountErrorCode.ACCOUNT_NOT_FOUND::accountException); - autoMoneyChange(myAccount, money, chargeLimitPk); + autoMoneyChange(myAccount, money); mainAccountRepository.save(myAccount); // 2. 이체 로그를 남겨준다. SendRecord sendRecord = new SendRecord(senderPk, depositPk, money); @@ -110,16 +104,18 @@ public boolean isSendValid(long myMoney, long sendMoney) { * * 메인 계좌의 돈을 자동으로 차감 또는 충전 후 차감 해주는 메소드 */ - public void autoMoneyChange(MainAccount mainAccount, long money, long chargeLimitPk) { + public void autoMoneyChange(MainAccount mainAccount, long money) { // 잔고가 부족한 경우 자동 충전 시작 if (!isSendValid(mainAccount.getMoney(), money)) { long minusMoney = money - mainAccount.getMoney(); // chargeMoney 계산 편의를 위해(양수로 만들기 위해) money - mainAccount.getMoney() - long chargeMoney = (minusMoney / ConstValue.LimitConst.CHARGE_AMOUNT + 1) - * ConstValue.LimitConst.CHARGE_AMOUNT; // 만 원 단위로 충전해야 할 금액 - checkAndCharge(chargeMoney, chargeLimitPk); // 충전 한도 확인 및 변화 - chargeMoney = chargeMoney - money; // 실제로 계좌에 더해야 하는 금액 - mainAccount.chargeMoney(chargeMoney); + long chargeMoney = minusMoney / ConstValue.LimitConst.CHARGE_AMOUNT; + if (minusMoney % ConstValue.LimitConst.CHARGE_AMOUNT > 0) { + chargeMoney++; + } + chargeMoney *= ConstValue.LimitConst.CHARGE_AMOUNT; + checkAndCharge(chargeMoney, mainAccount); // 충전 한도 확인 및 변화 + mainAccount.minusMoney(money); } else { mainAccount.minusMoney(money); } @@ -129,14 +125,10 @@ public void autoMoneyChange(MainAccount mainAccount, long money, long chargeLimi * * 충전 한도 테이블에서 충전 한도를 확인하고 가능하면 충전해주는 메소드 */ - public void checkAndCharge(long money, long chargeLimitPk) { - ChargeLimit chargeLimit = chargeLimitRepository.findByPkForUpdate(chargeLimitPk).orElseThrow(() -> - AccountErrorCode.CHARGE_LIMIT_NOT_FOUND.accountException( - "충전 한도 정보를 찾을 수 없음, chargeLimitPk = " + chargeLimitPk) - ); - if (!chargeLimit.charge(money)) { + public void checkAndCharge(long money, MainAccount mainAccount) { + mainAccount.chargeCheck(); + if (!mainAccount.charge(money)) { throw AccountErrorCode.CHARGE_LIMIT_EXCESS.accountException("충전 한도 초과, money = " + money); } - chargeLimitRepository.save(chargeLimit); } } diff --git a/src/main/java/org/c4marathon/assignment/common/entity/BaseEntity.java b/src/main/java/org/c4marathon/assignment/common/entity/BaseEntity.java index f5f6181d7..690fd9b18 100644 --- a/src/main/java/org/c4marathon/assignment/common/entity/BaseEntity.java +++ b/src/main/java/org/c4marathon/assignment/common/entity/BaseEntity.java @@ -25,4 +25,8 @@ public class BaseEntity { @LastModifiedDate @Column(name = "updated_at", nullable = false) private LocalDateTime updatedAt; + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } } diff --git a/src/main/java/org/c4marathon/assignment/member/dto/request/SignUpRequestDto.java b/src/main/java/org/c4marathon/assignment/member/dto/request/SignUpRequestDto.java index 99f629154..5e1d56f4b 100644 --- a/src/main/java/org/c4marathon/assignment/member/dto/request/SignUpRequestDto.java +++ b/src/main/java/org/c4marathon/assignment/member/dto/request/SignUpRequestDto.java @@ -34,14 +34,13 @@ public Member toEntity(String encodedPassword) { .build(); } - public Member toEntity(long mainAccountPk, long chargeLimitPk, String encodedPassword) { + public Member toEntity(long mainAccountPk, String encodedPassword) { return Member.builder() .memberId(memberId) .password(encodedPassword) .memberName(memberName) .phoneNumber(phoneNumber) .mainAccountPk(mainAccountPk) - .chargeLimitPk(chargeLimitPk) .build(); } } diff --git a/src/main/java/org/c4marathon/assignment/member/entity/Member.java b/src/main/java/org/c4marathon/assignment/member/entity/Member.java index 491fe9695..6f76581bf 100644 --- a/src/main/java/org/c4marathon/assignment/member/entity/Member.java +++ b/src/main/java/org/c4marathon/assignment/member/entity/Member.java @@ -42,21 +42,16 @@ public class Member extends BaseEntity { @Column(name = "main_account_pk", nullable = false) private long mainAccountPk; - @Column(name = "charge_limit_pk", nullable = false) - private long chargeLimitPk; - @OneToMany(mappedBy = "member") List savingAccounts = new ArrayList<>(); @Builder - public Member(String memberId, String password, String memberName, String phoneNumber, long mainAccountPk, - long chargeLimitPk) { + public Member(String memberId, String password, String memberName, String phoneNumber, long mainAccountPk) { this.memberId = memberId; this.password = password; this.memberName = memberName; this.phoneNumber = phoneNumber; this.mainAccountPk = mainAccountPk; - this.chargeLimitPk = chargeLimitPk; } } diff --git a/src/main/java/org/c4marathon/assignment/member/service/MemberService.java b/src/main/java/org/c4marathon/assignment/member/service/MemberService.java index ec3814e33..21a552dd5 100644 --- a/src/main/java/org/c4marathon/assignment/member/service/MemberService.java +++ b/src/main/java/org/c4marathon/assignment/member/service/MemberService.java @@ -1,8 +1,6 @@ package org.c4marathon.assignment.member.service; -import org.c4marathon.assignment.bankaccount.entity.ChargeLimit; import org.c4marathon.assignment.bankaccount.entity.MainAccount; -import org.c4marathon.assignment.bankaccount.repository.ChargeLimitRepository; import org.c4marathon.assignment.bankaccount.repository.MainAccountRepository; import org.c4marathon.assignment.member.dto.request.SignInRequestDto; import org.c4marathon.assignment.member.dto.request.SignUpRequestDto; @@ -24,7 +22,6 @@ public class MemberService { private final MemberRepository memberRepository; private final MainAccountRepository mainAccountRepository; private final PasswordEncoder passwordEncoder; - private final ChargeLimitRepository chargeLimitRepository; @Transactional public void signUp(SignUpRequestDto requestDto) { @@ -34,11 +31,8 @@ public void signUp(SignUpRequestDto requestDto) { MainAccount mainAccount = new MainAccount(); mainAccountRepository.save(mainAccount); - ChargeLimit chargeLimit = new ChargeLimit(); - chargeLimitRepository.save(chargeLimit); - String encodedPassword = passwordEncoder.encode(requestDto.password()); - Member member = requestDto.toEntity(mainAccount.getAccountPk(), chargeLimit.getLimitPk(), encodedPassword); + Member member = requestDto.toEntity(mainAccount.getAccountPk(), encodedPassword); memberRepository.save(member); } @@ -52,8 +46,7 @@ public SessionMemberInfo signIn(SignInRequestDto requestDto) { throw MemberErrorCode.INVALID_PASSWORD.memberException("비밀번호 불일치"); } - return new SessionMemberInfo(member.getMemberPk(), member.getMemberId(), member.getMainAccountPk(), - member.getChargeLimitPk()); + return new SessionMemberInfo(member.getMemberPk(), member.getMemberId(), member.getMainAccountPk()); } public MemberInfoResponseDto getMemberInfo(long memberPk) { diff --git a/src/main/java/org/c4marathon/assignment/member/session/SessionMemberInfo.java b/src/main/java/org/c4marathon/assignment/member/session/SessionMemberInfo.java index 246f94e23..4696fef1f 100644 --- a/src/main/java/org/c4marathon/assignment/member/session/SessionMemberInfo.java +++ b/src/main/java/org/c4marathon/assignment/member/session/SessionMemberInfo.java @@ -5,7 +5,6 @@ public record SessionMemberInfo( long memberPk, String memberId, - long mainAccountPk, - long chargeLimitPk + long mainAccountPk ) implements Serializable { } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4ad09f313..76810435c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -25,12 +25,6 @@ spring: use_sql_comments: true open-in-view: false - # Redis - data: - redis: - host: ${redis.host} - port: ${redis.port} - password: ${redis.password} logging: level: diff --git a/src/test/java/org/c4marathon/assignment/bankaccount/concurrency/MoneySendConcurrencyTest.java b/src/test/java/org/c4marathon/assignment/bankaccount/concurrency/MoneySendConcurrencyTest.java index 7c569e795..33ade0e9e 100644 --- a/src/test/java/org/c4marathon/assignment/bankaccount/concurrency/MoneySendConcurrencyTest.java +++ b/src/test/java/org/c4marathon/assignment/bankaccount/concurrency/MoneySendConcurrencyTest.java @@ -1,15 +1,12 @@ package org.c4marathon.assignment.bankaccount.concurrency; -import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; -import org.c4marathon.assignment.bankaccount.entity.ChargeLimit; import org.c4marathon.assignment.bankaccount.entity.MainAccount; import org.c4marathon.assignment.bankaccount.entity.SavingAccount; -import org.c4marathon.assignment.bankaccount.repository.ChargeLimitRepository; import org.c4marathon.assignment.bankaccount.repository.MainAccountRepository; import org.c4marathon.assignment.bankaccount.repository.SavingAccountRepository; import org.c4marathon.assignment.bankaccount.service.MainAccountService; @@ -24,16 +21,9 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.springframework.test.context.DynamicPropertySource; -import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import com.redis.testcontainers.RedisContainer; import static org.junit.jupiter.api.Assertions.*; @@ -43,20 +33,6 @@ @Testcontainers public class MoneySendConcurrencyTest { - private static final String REDIS_IMAGE = "redis:latest"; - private static final int REDIS_PORT = 6379; - - @Container - private static RedisContainer redis = new RedisContainer(DockerImageName.parse(REDIS_IMAGE)).withExposedPorts( - REDIS_PORT); - - @DynamicPropertySource - private static void redisProperties(DynamicPropertyRegistry registry) { - redis.start(); - registry.add("spring.data.redis.host", redis::getHost); - registry.add("spring.data.redis.port", redis::getFirstMappedPort); - } - @Autowired MemberRepository memberRepository; @@ -66,12 +42,9 @@ private static void redisProperties(DynamicPropertyRegistry registry) { @Autowired SavingAccountRepository savingAccountRepository; - @Autowired - ChargeLimitRepository chargeLimitRepository; @Autowired MainAccountService mainAccountService; - @Autowired - RedisTemplate redisTemplate; + @Autowired @Qualifier("depositExecutor") ThreadPoolTaskExecutor executor; @@ -79,10 +52,8 @@ private static void redisProperties(DynamicPropertyRegistry registry) { private Member[] member; private MainAccount mainAccount; private SavingAccount savingAccount; - private ChargeLimit chargeLimit; private long[] mainAccountPk; private long[] savingAccountPk; - private long[] chargeLimitPk; @Nested @DisplayName("메인 계좌에서 적금 계좌 송금시 동시성 테스트") @@ -117,9 +88,8 @@ void concurrency_send_to_saving_account_and_my_account() throws InterruptedExcep for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { - mainAccountService.sendToSavingAccount(mainAccountPk[0], savingAccountPk[0], savingPlusMoney, - chargeLimitPk[0]); - mainAccountService.chargeMoney(mainAccountPk[0], mainPlusMoney, chargeLimitPk[0]); + mainAccountService.sendToSavingAccount(mainAccountPk[0], savingAccountPk[0], savingPlusMoney); + mainAccountService.chargeMoney(mainAccountPk[0], mainPlusMoney); successCount.getAndIncrement(); } catch (Exception exception) { failCount.getAndIncrement(); @@ -159,8 +129,7 @@ void concurrency_send_to_saving_account() throws InterruptedException { for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { - mainAccountService.sendToSavingAccount(mainAccountPk[0], savingAccountPk[0], sendMoney, - chargeLimitPk[0]); + mainAccountService.sendToSavingAccount(mainAccountPk[0], savingAccountPk[0], sendMoney); successCount.getAndIncrement(); } catch (Exception exception) { failCount.getAndIncrement(); @@ -216,8 +185,7 @@ void concurrency_send_to_other_account_with_same_condition() throws InterruptedE // j번째 사람은 다음 순서의 사용자 메인 계좌에 이체 작업을 수행한다 for (int j = 0; j < 3; j++) { mainAccountService.sendToOtherAccount(mainAccountPk[j], mainAccountPk[(j + 1) % 3], - sendMoney, - chargeLimitPk[j]); + sendMoney); } successCount.getAndIncrement(); } catch (Exception exception) { @@ -278,8 +246,7 @@ void concurrency_send_to_other_account_with_different_condition() throws Interru // j번째 사람은 다음 순서의 사용자 메인 계좌에 이체 작업을 수행한다 for (int j = 0; j < 3; j++) { mainAccountService.sendToOtherAccount(mainAccountPk[j], mainAccountPk[(j + 1) % 3], - sendMoney[j], - chargeLimitPk[j]); + sendMoney[j]); } successCount.getAndIncrement(); } catch (Exception exception) { @@ -340,8 +307,7 @@ void concurrency_send_to_one_account_with_different_condition() throws Interrupt // j번째 사람은 다음 순서의 사용자 메인 계좌에 이체 작업을 수행한다 for (int j = 0; j < 2; j++) { mainAccountService.sendToOtherAccount(mainAccountPk[j], mainAccountPk[2], - sendMoney[j], - chargeLimitPk[j]); + sendMoney[j]); } successCount.getAndIncrement(); } catch (Exception exception) { @@ -382,23 +348,19 @@ void concurrency_send_to_one_account_with_different_condition() throws Interrupt void createAccount() { mainAccountPk = new long[3]; savingAccountPk = new long[3]; - chargeLimitPk = new long[3]; member = new Member[3]; for (int i = 0; i < 3; i++) { int money = 100000; - mainAccount = new MainAccount(money); + mainAccount = new MainAccount(); + mainAccount.charge(money); mainAccountRepository.save(mainAccount); - chargeLimit = new ChargeLimit(); - chargeLimitRepository.save(chargeLimit); - member[i] = Member.builder() .memberId("testId" + i) .password("testPass" + i) .memberName("testName" + i) .phoneNumber("testPhone" + i) .mainAccountPk(mainAccount.getAccountPk()) - .chargeLimitPk(chargeLimit.getLimitPk()) .build(); memberRepository.save(member[i]); @@ -408,20 +370,16 @@ void createAccount() { mainAccountPk[i] = mainAccount.getAccountPk(); savingAccountPk[i] = savingAccount.getAccountPk(); - chargeLimitPk[i] = chargeLimit.getLimitPk(); } - System.out.println("mainaccountpk = " + Arrays.toString(mainAccountPk)); } void clearAccount() { for (int i = 0; i < 3; i++) { savingAccount = savingAccountRepository.findById(savingAccountPk[i]).get(); mainAccount = mainAccountRepository.findById(mainAccountPk[i]).get(); - chargeLimit = chargeLimitRepository.findById(chargeLimitPk[i]).get(); savingAccountRepository.delete(savingAccount); mainAccountRepository.delete(mainAccount); memberRepository.delete(member[i]); - chargeLimitRepository.delete(chargeLimit); } } } diff --git a/src/test/java/org/c4marathon/assignment/bankaccount/controller/MainAccountControllerTest.java b/src/test/java/org/c4marathon/assignment/bankaccount/controller/MainAccountControllerTest.java index 13c3e641b..b3eb4d156 100644 --- a/src/test/java/org/c4marathon/assignment/bankaccount/controller/MainAccountControllerTest.java +++ b/src/test/java/org/c4marathon/assignment/bankaccount/controller/MainAccountControllerTest.java @@ -6,6 +6,7 @@ import org.c4marathon.assignment.bankaccount.dto.request.SendMoneyRequestDto; import org.c4marathon.assignment.bankaccount.dto.response.MainAccountResponseDto; import org.c4marathon.assignment.bankaccount.service.MainAccountService; +import org.c4marathon.assignment.common.utils.ConstValue; import org.c4marathon.assignment.member.session.SessionConst; import org.c4marathon.assignment.member.session.SessionMemberInfo; import org.junit.jupiter.api.BeforeEach; @@ -45,7 +46,7 @@ class MainAccountControllerTest { @BeforeEach void initSession() { session = new MockHttpSession(); - SessionMemberInfo memberInfo = new SessionMemberInfo(1L, "testId", 1L, 1L); + SessionMemberInfo memberInfo = new SessionMemberInfo(1L, "testId", 1L); session.setAttribute(SessionConst.MEMBER_INFO, memberInfo); } @@ -61,10 +62,9 @@ void request_with_a_valid_form() throws Exception { // Given SessionMemberInfo memberInfo = (SessionMemberInfo)session.getAttribute(SessionConst.MEMBER_INFO); long mainAccountPk = memberInfo.mainAccountPk(); - long chargeLimitPk = memberInfo.chargeLimitPk(); ChargeMoneyRequestDto requestDto = new ChargeMoneyRequestDto(money); - given(mainAccountService.chargeMoney(mainAccountPk, money, chargeLimitPk)).willReturn(baseMoney + money); + given(mainAccountService.chargeMoney(mainAccountPk, money)).willReturn(baseMoney + money); // When ResultActions resultActions = mockMvc.perform( @@ -160,7 +160,8 @@ class GetMainAccountInfo { @DisplayName("로그인한 사용자는 메인 계좌 조회에 성공한다") void request_with_login_member() throws Exception { // Given - MainAccountResponseDto responseDto = new MainAccountResponseDto(1L, 0); + MainAccountResponseDto responseDto = new MainAccountResponseDto(1L, ConstValue.LimitConst.CHARGE_LIMIT, + ConstValue.LimitConst.CHARGE_LIMIT, 0); given(mainAccountService.getMainAccountInfo(anyLong())).willReturn(responseDto); // When diff --git a/src/test/java/org/c4marathon/assignment/bankaccount/controller/SavingAccountControllerTest.java b/src/test/java/org/c4marathon/assignment/bankaccount/controller/SavingAccountControllerTest.java index 5265190b5..5732274b8 100644 --- a/src/test/java/org/c4marathon/assignment/bankaccount/controller/SavingAccountControllerTest.java +++ b/src/test/java/org/c4marathon/assignment/bankaccount/controller/SavingAccountControllerTest.java @@ -49,7 +49,7 @@ class SavingAccountControllerTest { @BeforeEach public void setSession() { session = new MockHttpSession(); - SessionMemberInfo sessionMemberInfo = new SessionMemberInfo(1L, "testId", 1L, 1L); + SessionMemberInfo sessionMemberInfo = new SessionMemberInfo(1L, "testId", 1L); session.setAttribute(SessionConst.MEMBER_INFO, sessionMemberInfo); } diff --git a/src/test/java/org/c4marathon/assignment/bankaccount/service/MainAccountServiceTest.java b/src/test/java/org/c4marathon/assignment/bankaccount/service/MainAccountServiceTest.java index a4a25e804..0c4239174 100644 --- a/src/test/java/org/c4marathon/assignment/bankaccount/service/MainAccountServiceTest.java +++ b/src/test/java/org/c4marathon/assignment/bankaccount/service/MainAccountServiceTest.java @@ -1,14 +1,13 @@ package org.c4marathon.assignment.bankaccount.service; +import java.time.LocalDateTime; import java.util.Optional; import org.c4marathon.assignment.bankaccount.dto.response.MainAccountResponseDto; -import org.c4marathon.assignment.bankaccount.entity.ChargeLimit; import org.c4marathon.assignment.bankaccount.entity.MainAccount; import org.c4marathon.assignment.bankaccount.entity.SavingAccount; import org.c4marathon.assignment.bankaccount.exception.AccountErrorCode; import org.c4marathon.assignment.bankaccount.exception.AccountException; -import org.c4marathon.assignment.bankaccount.repository.ChargeLimitRepository; import org.c4marathon.assignment.bankaccount.repository.MainAccountRepository; import org.c4marathon.assignment.bankaccount.repository.SavingAccountRepository; import org.c4marathon.assignment.bankaccount.repository.SendRecordRepository; @@ -36,8 +35,6 @@ class MainAccountServiceTest { @Mock SavingAccountRepository savingAccountRepository; @Mock - ChargeLimitRepository chargeLimitRepository; - @Mock SendRecordRepository sendRecordRepository; @Mock DepositHandlerService depositHandlerService; @@ -48,18 +45,16 @@ class ChargeMoney { long mainAccountPk = 1L; int money = 1000; int accountMoney = 0; - long chargeLimitPk = 1L; @Test @DisplayName("계좌가 있고 충전 한도를 벗어나지 않으면 정상 충전된다.") void request_with_valid_account_and_charging_limit() { // Given - MainAccount mainAccount = new MainAccount(accountMoney); + MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); given(mainAccountRepository.findByPkForUpdate(mainAccountPk)).willReturn(Optional.of(mainAccount)); - ChargeLimit chargeLimit = new ChargeLimit(); - given(chargeLimitRepository.findByPkForUpdate(chargeLimitPk)).willReturn(Optional.of(chargeLimit)); // When - long returnValue = mainAccountService.chargeMoney(mainAccountPk, money, chargeLimitPk); + long returnValue = mainAccountService.chargeMoney(mainAccountPk, money); // Then assertEquals(returnValue, accountMoney + money); @@ -69,13 +64,14 @@ void request_with_valid_account_and_charging_limit() { @DisplayName("충전 한도를 초과하면 AccountException(CHARGE_LIMIT_EXCESS) 예외가 발생한다.") void request_with_over_charge_limit() { // Given - ChargeLimit chargeLimit = new ChargeLimit(); - chargeLimit.charge(chargeLimit.getSpareMoney()); - given(chargeLimitRepository.findByPkForUpdate(chargeLimitPk)).willReturn(Optional.of(chargeLimit)); + MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); + mainAccount.charge(ConstValue.LimitConst.CHARGE_LIMIT); + given(mainAccountRepository.findByPkForUpdate(mainAccountPk)).willReturn(Optional.of(mainAccount)); // When AccountException accountException = assertThrows(AccountException.class, () -> { - mainAccountService.chargeMoney(mainAccountPk, money, chargeLimitPk); + mainAccountService.chargeMoney(mainAccountPk, money); }); // Then @@ -86,13 +82,11 @@ void request_with_over_charge_limit() { @DisplayName("메인 계좌가 생성되지 않은 사용자라면 AccountException(ACCOUNT_NOT_FOUND) 예외가 발생한다.") void request_with_no_main_account() { // Given - ChargeLimit chargeLimit = new ChargeLimit(); given(mainAccountRepository.findByPkForUpdate(mainAccountPk)).willReturn(Optional.empty()); - given(chargeLimitRepository.findByPkForUpdate(chargeLimitPk)).willReturn(Optional.of(chargeLimit)); // When AccountException accountException = assertThrows(AccountException.class, () -> { - mainAccountService.chargeMoney(mainAccountPk, money, chargeLimitPk); + mainAccountService.chargeMoney(mainAccountPk, money); }); // Then @@ -114,11 +108,12 @@ void request_with_exist_accounts_and_valid_send_money() { SavingAccount savingAccount = new SavingAccount("free", 500); given(savingAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(savingAccount)); - MainAccount mainAccount = new MainAccount(myMoney); + MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); given(mainAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(mainAccount)); // When - mainAccountService.sendToSavingAccount(1, 1, sendMoney, 1); + mainAccountService.sendToSavingAccount(1, 1, sendMoney); // Then assertEquals(savingAccount.getSavingMoney(), sendMoney); @@ -129,13 +124,14 @@ void request_with_exist_accounts_and_valid_send_money() { @DisplayName("적금 계좌가 없으면 AccountException(ACCOUNT_NOT_FOUND) 예외가 발생한다.") void request_with_no_main_account() { // Given - MainAccount mainAccount = new MainAccount(sendMoney); + MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); given(mainAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(mainAccount)); given(savingAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.empty()); // When AccountException accountException = assertThrows(AccountException.class, - () -> mainAccountService.sendToSavingAccount(1, 1, sendMoney, 1)); + () -> mainAccountService.sendToSavingAccount(1, 1, sendMoney)); // Then assertEquals(AccountErrorCode.ACCOUNT_NOT_FOUND.name(), accountException.getErrorName()); @@ -149,7 +145,7 @@ void request_with_no_saving_account() { // When AccountException accountException = assertThrows(AccountException.class, - () -> mainAccountService.sendToSavingAccount(1, 1, sendMoney, 1)); + () -> mainAccountService.sendToSavingAccount(1, 1, sendMoney)); // Then assertEquals(AccountErrorCode.ACCOUNT_NOT_FOUND.name(), accountException.getErrorName()); @@ -203,14 +199,12 @@ void send_to_other_account_success() { long senderPk = 1L; long depositPk = 2L; long money = 1000; - long chargeLimitPk = 1L; MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); given(mainAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(mainAccount)); - ChargeLimit chargeLimit = new ChargeLimit(); - given(chargeLimitRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(chargeLimit)); // When - mainAccountService.sendToOtherAccount(senderPk, depositPk, money, chargeLimitPk); + mainAccountService.sendToOtherAccount(senderPk, depositPk, money); // Then then(mainAccountRepository).should(times(1)).findByPkForUpdate(anyLong()); @@ -231,32 +225,12 @@ void request_with_non_valid_accountPk() { // When AccountException accountException = assertThrows(AccountException.class, - () -> mainAccountService.sendToOtherAccount(senderPk, depositPk, money, chargeLimitPk)); + () -> mainAccountService.sendToOtherAccount(senderPk, depositPk, money)); // Then assertEquals(accountException.getErrorName(), AccountErrorCode.ACCOUNT_NOT_FOUND.name()); } - @Test - @DisplayName("충전 한도 정보가 없으면 AccountException(CHARGE_LIMIT_NOT_FOUND) 예외가 발생한다.") - void request_with_non_valid_chargeLimitPk() { - // Given - long senderPk = 1L; - long depositPk = 2L; - long money = 1000; - long chargeLimitPk = 1L; - MainAccount mainAccount = new MainAccount(); - given(mainAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(mainAccount)); - given(chargeLimitRepository.findByPkForUpdate(anyLong())).willReturn(Optional.empty()); - - // When - AccountException accountException = assertThrows(AccountException.class, - () -> mainAccountService.sendToOtherAccount(senderPk, depositPk, money, chargeLimitPk)); - - // Then - assertEquals(accountException.getErrorName(), AccountErrorCode.CHARGE_LIMIT_NOT_FOUND.name()); - } - @Test @DisplayName("충전 한도를 초과하면 AccountException(CHARGE_LIMIT_EXCESS) 예외가 발생한다.") void request_with_no_spare_money() { @@ -264,16 +238,16 @@ void request_with_no_spare_money() { long senderPk = 1L; long depositPk = 2L; long money = 1000; - long chargeLimitPk = 1L; MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); + mainAccount.charge(ConstValue.LimitConst.CHARGE_LIMIT); + mainAccount.minusMoney(ConstValue.LimitConst.CHARGE_LIMIT); + given(mainAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(mainAccount)); - ChargeLimit chargeLimit = new ChargeLimit(); - chargeLimit.charge(ConstValue.LimitConst.CHARGE_LIMIT); - given(chargeLimitRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(chargeLimit)); // When AccountException accountException = assertThrows(AccountException.class, - () -> mainAccountService.sendToOtherAccount(senderPk, depositPk, money, chargeLimitPk)); + () -> mainAccountService.sendToOtherAccount(senderPk, depositPk, money)); // Then assertEquals(accountException.getErrorName(), AccountErrorCode.CHARGE_LIMIT_EXCESS.name()); @@ -286,14 +260,12 @@ void request_with_over_money() { long senderPk = 1L; long depositPk = 2L; long money = 1000; - long chargeLimitPk = 1L; MainAccount mainAccount = new MainAccount(); + mainAccount.setUpdatedAt(LocalDateTime.now()); given(mainAccountRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(mainAccount)); - ChargeLimit chargeLimit = new ChargeLimit(); - given(chargeLimitRepository.findByPkForUpdate(anyLong())).willReturn(Optional.of(chargeLimit)); // When - mainAccountService.sendToOtherAccount(senderPk, depositPk, money, chargeLimitPk); + mainAccountService.sendToOtherAccount(senderPk, depositPk, money); // Then assertEquals(ConstValue.LimitConst.CHARGE_AMOUNT - money, mainAccount.getMoney()); diff --git a/src/test/java/org/c4marathon/assignment/member/controller/MemberControllerTest.java b/src/test/java/org/c4marathon/assignment/member/controller/MemberControllerTest.java index e77ea0d7f..b4c5025c3 100644 --- a/src/test/java/org/c4marathon/assignment/member/controller/MemberControllerTest.java +++ b/src/test/java/org/c4marathon/assignment/member/controller/MemberControllerTest.java @@ -226,7 +226,7 @@ class SignIn { void request_with_valid_id_and_password() throws Exception { // Given SignInRequestDto requestDto = new SignInRequestDto("testId", "password"); - SessionMemberInfo memberDto = new SessionMemberInfo(1L, "testId", 0L, 1L); + SessionMemberInfo memberDto = new SessionMemberInfo(1L, "testId", 0L); given(memberService.signIn(requestDto)).willReturn(memberDto); // When @@ -289,7 +289,7 @@ class GetMyInfo { @DisplayName("로그인한 사용자는 자신의 정보를 반환받는다.") void request_with_login_member() throws Exception { // Given - SessionMemberInfo sessionMemberInfo = new SessionMemberInfo(1L, "testId", 0L, 1L); + SessionMemberInfo sessionMemberInfo = new SessionMemberInfo(1L, "testId", 0L); MockHttpSession session = new MockHttpSession(); session.setAttribute(SessionConst.MEMBER_INFO, sessionMemberInfo); diff --git a/src/test/java/org/c4marathon/assignment/member/service/MemberServiceImplTest.java b/src/test/java/org/c4marathon/assignment/member/service/MemberServiceImplTest.java index 90d290f0c..b7c203826 100644 --- a/src/test/java/org/c4marathon/assignment/member/service/MemberServiceImplTest.java +++ b/src/test/java/org/c4marathon/assignment/member/service/MemberServiceImplTest.java @@ -2,9 +2,7 @@ import java.util.Optional; -import org.c4marathon.assignment.bankaccount.entity.ChargeLimit; import org.c4marathon.assignment.bankaccount.entity.MainAccount; -import org.c4marathon.assignment.bankaccount.repository.ChargeLimitRepository; import org.c4marathon.assignment.bankaccount.repository.MainAccountRepository; import org.c4marathon.assignment.member.dto.request.SignInRequestDto; import org.c4marathon.assignment.member.dto.request.SignUpRequestDto; @@ -36,8 +34,6 @@ class MemberServiceImplTest { MainAccountRepository mainAccountRepository; @Mock PasswordEncoder passwordEncoder; - @Mock - ChargeLimitRepository chargeLimitRepository; @Nested @DisplayName("회원 가입 테스트") @@ -51,10 +47,8 @@ void request_with_non_duplicated_id() { SignUpRequestDto requestDto = makeRequestForm(); given(memberRepository.findMemberByMemberId(requestDto.memberId())).willReturn(null); MainAccount mainAccount = new MainAccount(); - ChargeLimit chargeLimit = new ChargeLimit(); given(mainAccountRepository.save(any())).willReturn(mainAccount); - given(chargeLimitRepository.save(any())).willReturn(chargeLimit); // When memberService.signUp(requestDto);