From 3b205f3ed64a917255954af0fdfe5eeebe28d54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 12:30:39 +0900 Subject: [PATCH 01/32] =?UTF-8?q?chore=20:=20=EB=AA=A8=EB=8D=B8=EB=A7=81?= =?UTF-8?q?=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 175 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index be90e7f..8d8b21f 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,183 @@ -# 2주차 +# 2주차 + ## 이츠 페이먼츠 ( EST's-Payments ) -이스트소프트는 최근 금융사업과 관련하여 송금 서비스를 제공하기로 결정되었다. 각 서비스들은 MSA로 분리되어있다. -
-베타서비스를 위해, A2개발팀은 송금과 관련된 요구사항이 부여되었고 개발자들은 해당 요구사항을 토대로 개발을 진행해야한다. +이스트소프트는 최근 금융사업과 관련하여 송금 서비스를 제공하기로 결정되었다. 각 서비스들은 MSA로 분리되어있다. +
+ +베타서비스를 위해, A2개발팀은 송금과 관련된 요구사항이 부여되었고 개발자들은 해당 요구사항을 토대로 개발을 진행해야한다. + +## 요구사항 -## 요구사항 1. 사용자는 돈이 없으면 송금할 수 없다. 2. 동일한 송금은 두번 요청할 수 없다. 3. 송금 후에는 계좌잔액을 노출해야 한다. 4. 송금 내역은 5개월동안 보장되고 그 이후의 내역은 삭제되어야 한다. +> 송금 이력이 사라지기 때문에 계좌 잔액을 영속화하거나 송금 기록을 제외한 입출금 내역만을 관리해 계좌 잔액을 계산해야 한다. + +## 요구사항 정제 + +- `계좌 번호`를 입력해 `계좌`를 생성한다. + - `계좌 번호`는 10자리로 구성되어있다. + - `계좌 번호`는 중복되어서는 안된다. +- `자신 계좌 번호`와 `상대방 계좌 번호` 그리고 `돈의 수량`을 입력해 송금을 진행 한 후 계좌 잔액을 노출한다. + - `상대방 계좌 번호`가 존재하지 않으면 안된다. + - `자신 계좌 번호`가 존재하지 않으면 안된다. + - `자신 계좌 번호`와 `상대방 계좌 번호`가 동일하면 안된다. + - `돈의 수량`은 0보다 커야한다. + - `자신 계좌`에 잔액이 입력한 `돈의 수량`보다 많아야 한다. + - 동일한 송금은 두번 요청할 수 없다. + - `자신 계좌`에서 `상대방의 계좌`로 돈을 전달한다. + - 송금한 기록을 남긴다. 송금 기록에는 `자신의 계좌 번호`, `상대방 계좌 번호`, `송금한 돈의 수량`, `송금한 일자`가 포함된다. + - 송금 후 `자신 계좌` 잔액을 노출한다. +- `계좌 번호`, `돈의 수량`를 입력해 돈을 입급한다. + - `계좌 번호`가 존재하지 않으면 안된다. + - `돈의 수량`은 0보다 커야한다. +- `계좌 번호`, `돈의 수량`를 입력해 돈을 출금한다. + - `계좌 번호`가 존재하지 않으면 안된다. + - `돈의 수량`은 0보다 커야한다. + - `계좌`에 잔액이 입력한 `돈의 수량`보다 많아야 한다. + +## 모델링 + +| 한글 | 영어 | 설명 | +|-----------|--------------------|-----------------------------------------------------------------| +| 송금 | Transfer | 송금에는 `송금한 계좌`, `송금받은 계좌`, `송금한 돈의 수량`, `송금한 일자`가 포함된다. | +| 송금한 계좌 | sourceAccount | 송금하려는 계좌 정보. | +| 송금받은 계좌 | targetAccount | 송금받는 계좌 정보. | +| 송금한 돈의 수량 | transferMoney | 송금할 돈의 수량. | +| 송금한 일자 | transferDate | 송금한 일자는 송금한 날짜. | +| 계좌 | Account | 계좌에는 `계좌 번호`, `생성 일자 정보`, `잔액 정보`, `송금 이력`을 포함한다. | +| 계좌 번호 | AccountNumber | 10자리로 구성된 고유한 값. | +| 생성 일자 | createDate | 계좌를 생성한 날짜. | +| 잔액 | balance | 계좌에 남은 돈의 수량. | +| 송금 이력 | transferHistories | 송금 이력에는 `송금한 계좌 번호`, `송금받은 계좌 번호`, `송금한 돈의 수량`, `송금한 일자`가 포함된다. | +| 돈 | Money | 주고받는 돈의 기본 단위. 돈의 수량은 0 이상이어야 한다. | +| 입출금 이력 | transactionHistory | 입출금 이력에는 `계좌 번호`, `입출금 타입`, `돈의 수량`, `입출금 일자`가 포함된다. | + +### 입금 + +- `계좌 번호(AccountNumber)`와 `돈의 수량(Money)`을 입력해 돈을 입금한다. +- `계좌 번호(AccountNumber)`가 존재하지 않으면 안된다. +- `돈의 수량(Money)`은 0보다 커야한다. +- `입출금 이력(transactionHisotry)`에 `입금 기록(DEPOSIT)`을 추가한다. + +### 출금 + +- `계좌 번호(AccountNumber)`와 `돈의 수량(Money)`을 입력해 돈을 출금한다. +- `계좌 번호(AccountNumber)`가 존재하지 않으면 안된다. +- `돈의 수량(Money)`은 0보다 커야한다. +- `계좌`에 잔액이 입력한 `돈의 수량(Money)`보다 많아야 한다. +- `입출금 이력(transactionHisotry)`에 `출금 기록(WITHDRAW)`을 추가한다. + +### 송금 + +- `자신 계좌(sourceAccount)`와 `상대방 계좌(targetAccount)`, `송금 일자(transferDate)` 그리고 `돈의 수량(transferMoney)`을 입력해 송금한다. +- `상대방 계좌(targetAccount)`가 존재하지 않으면 안된다. +- `자신 계좌(sourceAccount)`가 존재하지 않으면 안된다. +- `자신 계좌(sourceAccount)`와 `상대방 계좌(targetAccount)`가 동일하면 안된다. +- `돈의 수량(transferMoney)`은 0보다 커야한다. +- `자신 계좌(sourceAccount)`의 `입출금 이력(transactionHisotry)`에는 `출금 기록(WITHDRAW)`을 추가한다. +- `상대방 계좌(targetAccount)`의 `입출금 이력(transactionHisotry)`에는 `입금 기록(DEPOSIT)`을 추가한다. + +### 계좌 + +- 계좌에는 `계좌 번호(AccountNumber)`, `생성 일자 정보(createDate)`, `잔액 정보(balance)`, `송금 이력(transferHistories)`, `입출금 이력(transactionHisotry)`를 포함한다. +- `입출금 이력(transactionHisotry)` 에는 `계좌 번호(AccountNumber)`, `입출금 타입(type)`, `돈의 수량(Money)`, `입출금 일자(transactionDate)`가 포함된다. +- `입출금 이력(transactionHisotry)`으로 `잔액 정보(balance)`를 계산한다. +- `계좌 번호(AccountNumber)`는 10자리로 구성되어있다. +- `잔액 정보(balance)`는 0 이상이어야 한다. +- `송금 이력(transferHistories)` 에는 `송금한 계좌(sourceAccount)`, `송금받은 계좌(targetAccount)`, `송금한 돈의 수량(transferMoney)`, `송금한 일자(transferDate)`가 포함된다. + +### 돈(Money) + +- `금액 정보(amount)`가 포함된다. + +### 클래스 다이어그램 + +```mermaid +classDiagram + class Withdraw { + - Account targetAccount + - Money withdrawMoney + - Date withdrawDate + } + + class Deposit { + - Account targetAccount + - Money depositMoney + - Date depositDate + } + + class Transfer { + - Account sourceAccount + - Account targetAccount + - money transferMoney + - Date transferDate + } + + class Account { + - AccountNumber number + - Money balance + - List~TransferHistory~ transferHistories + - Date createdDate + } + + class AccountNumber { + - String number + } + + class TransferHistory { + - Account sourceAccount + - Account targetAccount + - Money transferMoney + - TransferDate transferDate + } + + class Money { + - int amount + } + + Withdraw *-- Account + Withdraw *-- Money + Deposit *-- Account + Deposit *-- Money + Account *-- AccountNumber + Account *-- Money + Account *-- TransferHistory + Transfer *-- Money + Transfer *-- Account + TransferHistory *-- Money + TransferHistory *-- Account +``` + +## erd + +```mermaid +erDiagram + transfer_history { + id long pk + source_account_id long fk + target_account_id long fk + transfer_money int + trasfer_date date + } + + account { + id long pk + account_number varchar(200) + created_date date + } + + account_transaction { + id long pk + account_id long fk + type enum "WITHDRAW, DEPOSIT" + money int + transaction_date date + } + + account ||--o{ transfer_history: has + account ||--o{ account_transaction: contains +``` From e3d2258a1ab470be1dfaea2dcdb23ef5d9fd6939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 15:01:42 +0900 Subject: [PATCH 02/32] =?UTF-8?q?chore=20:=20fixture=20monkey=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index c1d8c88..2ff49b8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,12 +24,15 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.boot:spring-boot-starter-validation") runtimeOnly("com.h2database:h2") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.junit.jupiter", "junit-jupiter", "5.8.2") testImplementation("org.assertj", "assertj-core", "3.22.0") testImplementation("io.kotest", "kotest-runner-junit5", "5.4.0") + testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter-kotlin:1.0.13") + testImplementation("com.navercorp.fixturemonkey:fixture-monkey-jakarta-validation:1.0.0") } tasks.withType { From ddb5912b60121b2f4dee634ea64c5d5642d01447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:04:33 +0900 Subject: [PATCH 03/32] =?UTF-8?q?chore=20:=20gitignore=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ecfb160..3d8b537 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,149 @@ -.DS_Store -.idea +# Created by https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,kotlin +# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all,gradle,kotlin + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Kotlin ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Gradle ### .gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# Fixture Monkey + +.jqwik-database + +# End of https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,kotlin From f7382bcd0ba19c163b586eb36e2a2803c56b3c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:13:55 +0900 Subject: [PATCH 04/32] =?UTF-8?q?feature=20:=20Money=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/domain/Money.kt | 30 ++++++++++++++++ .../example/estdelivery/domain/MoneyTest.kt | 35 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/Money.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/Money.kt b/src/main/kotlin/com/example/estdelivery/domain/Money.kt new file mode 100644 index 0000000..e71f52a --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/Money.kt @@ -0,0 +1,30 @@ +package com.example.estdelivery.domain + +import jakarta.validation.constraints.PositiveOrZero +import java.math.BigInteger + +class Money( + @field:PositiveOrZero + private val amount: BigInteger +) { + init { + require(amount >= BigInteger.ZERO) { "금액은 0원 이상이어야 합니다." } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Money + + return amount == other.amount + } + + override fun hashCode(): Int { + return amount.hashCode() + } + + override fun toString(): String { + return "Money(amount=$amount)" + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt new file mode 100644 index 0000000..8a55e31 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt @@ -0,0 +1,35 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import java.math.BigInteger + +class MoneyTest : FreeSpec({ + "0이상의 숫자를 넣어" - { + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + + for (i in 0..300) { + "$i 번째 금액을 생성한다." { + val giveMeBuilder = fixtureMonkey.giveMeBuilder() + shouldNotThrow { giveMeBuilder.sample() } + } + } + } + + "금액은 0원 이상이어야 한다." { + shouldThrow { + Money(BigInteger.valueOf(-1)) + }.message shouldBe "금액은 0원 이상이어야 합니다." + } +}) From 9e35dcb4066d7c2fcbd38d09fc78d036f33ff436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:19:42 +0900 Subject: [PATCH 05/32] =?UTF-8?q?chore=20:=20=EB=AA=A8=EB=8D=B8=EB=A7=81?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8d8b21f..8fe7da8 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ - `입출금 이력(transactionHisotry)`으로 `잔액 정보(balance)`를 계산한다. - `계좌 번호(AccountNumber)`는 10자리로 구성되어있다. - `잔액 정보(balance)`는 0 이상이어야 한다. -- `송금 이력(transferHistories)` 에는 `송금한 계좌(sourceAccount)`, `송금받은 계좌(targetAccount)`, `송금한 돈의 수량(transferMoney)`, `송금한 일자(transferDate)`가 포함된다. +- `송금 이력(transferHistories)` 에는 `송금한 계좌(sourceAccountNumber)`, `송금받은 계좌(targetAccountNumber)`, `송금한 돈의 수량(transferMoney)`, `송금한 일자(transferDate)`가 포함된다. ### 돈(Money) @@ -129,8 +129,8 @@ classDiagram } class TransferHistory { - - Account sourceAccount - - Account targetAccount + - AccountNumber sourceAccountNumber + - AccountNumber targetAccountNumber - Money transferMoney - TransferDate transferDate } @@ -149,7 +149,7 @@ classDiagram Transfer *-- Money Transfer *-- Account TransferHistory *-- Money - TransferHistory *-- Account + TransferHistory *-- AccountNumber ``` ## erd @@ -158,8 +158,8 @@ classDiagram erDiagram transfer_history { id long pk - source_account_id long fk - target_account_id long fk + source_account_number varchar(200) + target_account_number varchar(200) transfer_money int trasfer_date date } From 15f521730b046cd08b701be4d143134fd5ac6820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:21:48 +0900 Subject: [PATCH 06/32] =?UTF-8?q?refactor=20:=20Money=20data=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/domain/Money.kt | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/main/kotlin/com/example/estdelivery/domain/Money.kt b/src/main/kotlin/com/example/estdelivery/domain/Money.kt index e71f52a..6c6831e 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Money.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Money.kt @@ -3,28 +3,11 @@ package com.example.estdelivery.domain import jakarta.validation.constraints.PositiveOrZero import java.math.BigInteger -class Money( +data class Money( @field:PositiveOrZero private val amount: BigInteger ) { init { require(amount >= BigInteger.ZERO) { "금액은 0원 이상이어야 합니다." } } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Money - - return amount == other.amount - } - - override fun hashCode(): Int { - return amount.hashCode() - } - - override fun toString(): String { - return "Money(amount=$amount)" - } } From ae54557f466d9f980ea455be92d8ed6a2ca393aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:27:09 +0900 Subject: [PATCH 07/32] =?UTF-8?q?feature=20:=20AccountNumber=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/domain/AccountNumber.kt | 14 +++++++ .../estdelivery/domain/AccountNumberTest.kt | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt new file mode 100644 index 0000000..af4369a --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt @@ -0,0 +1,14 @@ +package com.example.estdelivery.domain + +import jakarta.validation.constraints.Pattern +import jakarta.validation.constraints.Size + +data class AccountNumber( + @field:Size(min = 10, max = 10) + @field:Pattern(regexp = "^[0-9]*$") + private val accountNumber: String +) { + init { + require(accountNumber.length == 10) { "계좌번호는 10자리여야 합니다." } + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt new file mode 100644 index 0000000..385d1a3 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt @@ -0,0 +1,38 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe + +class AccountNumberTest : FreeSpec({ + + "임의 번호를 생성해" - { + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + + for (i in 0..300) { + "$i 번째 계좌 번호를 생성한다." { + shouldNotThrow { + fixtureMonkey.giveMeBuilder().sample() + } + } + } + } + + "계좌번호는 10자리가 아니면 예외가 발생한다." { + val accountNumber = "123456789" + val exception = shouldThrow { + AccountNumber(accountNumber) + } + exception.message shouldBe "계좌번호는 10자리여야 합니다." + } +}) From c1667c1a07c7e09a240e40bb7a78bfe03b95d124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:37:56 +0900 Subject: [PATCH 08/32] =?UTF-8?q?feature=20:=20TransferHistory=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/domain/TransferHistory.kt | 17 +++++++ .../estdelivery/domain/TransferHistoryTest.kt | 51 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt new file mode 100644 index 0000000..d391d9f --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt @@ -0,0 +1,17 @@ +package com.example.estdelivery.domain + +import jakarta.validation.constraints.PastOrPresent +import java.time.LocalDateTime + +data class TransferHistory( + private val source: AccountNumber, + private val target: AccountNumber, + private val money: Money, + @field:PastOrPresent + private val transferDate: LocalDateTime +) { + init { + require(source != target) { "출금 계좌와 입금 계좌는 같을 수 없습니다." } + require(transferDate.isBefore(LocalDateTime.now())) { "이체 일자는 현재 일자보다 이전이어야 합니다." } + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt new file mode 100644 index 0000000..a74607b --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt @@ -0,0 +1,51 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FreeSpec +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import java.time.LocalDateTime + +class TransferHistoryTest : FreeSpec({ + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + + "300 번 중" - { + for (i in 0..300) { + "$i 번째 송금 내역을 생성한다." { + println(fixtureMonkey.giveMeBuilder().sample()) + } + } + } + + "입급 계좌와 출급 계좌가 같을 수 없다." { + val sameAccountNumber = fixtureMonkey.giveMeBuilder().sample() + val money = fixtureMonkey.giveMeBuilder().sample() + + shouldThrow { + TransferHistory(sameAccountNumber, sameAccountNumber, money, LocalDateTime.now()) + } + } + + "이체 일자는 현재 시간보다 이전이어야 한다." { + val futureDateTime = LocalDateTime.now().plusDays(1) + val money = fixtureMonkey.giveMeBuilder().sample() + + shouldThrow { + TransferHistory( + fixtureMonkey.giveMeBuilder().sample(), + fixtureMonkey.giveMeBuilder().sample(), + money, + futureDateTime + ) + } + } +}) From e98e4c22ba5d848f4a2590f2b564ec469cb6f7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 17:02:00 +0900 Subject: [PATCH 09/32] =?UTF-8?q?feature=20:=20TransferHistories=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/domain/TransferHistories.kt | 17 +++++++ .../domain/TransferHistoriesTest.kt | 50 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt new file mode 100644 index 0000000..b2a245d --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt @@ -0,0 +1,17 @@ +package com.example.estdelivery.domain + +class TransferHistories( + private var transferHistories: List +) { + fun showHistories(): List { + return transferHistories + } + + fun addHistory(transferHistory: TransferHistory) { + transferHistories = transferHistories + transferHistory + } + + fun removeHistory(transferHistory: TransferHistory) { + transferHistories = transferHistories - transferHistory + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt new file mode 100644 index 0000000..ab6a669 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt @@ -0,0 +1,50 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.core.spec.style.FreeSpec + +class TransferHistoriesTest : FreeSpec({ + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + + "이체 내역을 생성한다." { + val list = fixtureMonkey.giveMeBuilder>().sample() + + shouldNotThrow { + TransferHistories(list) + } + } + + "이체 내역을 조회한다." { + val histories = fixtureMonkey.giveMeBuilder().sample() + shouldNotThrow { + histories.showHistories() + } + } + + "이체 내역을 추가할 때" - { + val histories = fixtureMonkey.giveMeBuilder().sample() + for (i in 0..100) { + val transferHistory = fixtureMonkey.giveMeBuilder().sample() + "$i 번째 이력을 추가한다." { + shouldNotThrow { + histories.addHistory(transferHistory) + } + } + + "$i 번째 이력을 제거한다." { + shouldNotThrow { + histories.removeHistory(transferHistory) + } + } + } + } +}) From 29e39f24335b18862d234bc642280a665c67c913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sat, 17 Feb 2024 23:12:34 +0900 Subject: [PATCH 10/32] =?UTF-8?q?feature=20:=20Account=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/domain/Account.kt | 34 +++++++++++++ .../estdelivery/domain/TransferHistories.kt | 13 +++++ .../estdelivery/domain/TransferHistory.kt | 2 + .../example/estdelivery/domain/AccountTest.kt | 49 +++++++++++++++++++ .../domain/TransferHistoriesTest.kt | 24 +++++++++ 5 files changed, 122 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/Account.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/Account.kt b/src/main/kotlin/com/example/estdelivery/domain/Account.kt new file mode 100644 index 0000000..75ec1e2 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/Account.kt @@ -0,0 +1,34 @@ +package com.example.estdelivery.domain + +import jakarta.validation.constraints.PastOrPresent +import java.time.LocalDateTime + +class Account( + private val number: AccountNumber, + private val balance: Money, + private val transferHistories: TransferHistories, + @field:PastOrPresent + private val createdDate: LocalDateTime, + private val id: Long? = null +) { + init { + require(transferHistories.ensureMyHistories(number)) { "자신의 이력이 아닌 정보가 존재합니다." } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Account + + return id == other.id + } + + override fun hashCode(): Int { + return id?.hashCode() ?: 0 + } + + override fun toString(): String { + return "Account(number=$number, balance=$balance, transferHistories=$transferHistories, createdDate=$createdDate, id=$id)" + } +} diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt index b2a245d..ba90932 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt @@ -14,4 +14,17 @@ class TransferHistories( fun removeHistory(transferHistory: TransferHistory) { transferHistories = transferHistories - transferHistory } + + fun ensureMyHistories(number: AccountNumber): Boolean { + for (transferHistory in transferHistories) { + if (transferHistory.isMyHistory(number).not()) { + return false + } + } + return true + } + + override fun toString(): String { + return "TransferHistories(transferHistories=$transferHistories)" + } } diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt index d391d9f..3ae9c9e 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt @@ -14,4 +14,6 @@ data class TransferHistory( require(source != target) { "출금 계좌와 입금 계좌는 같을 수 없습니다." } require(transferDate.isBefore(LocalDateTime.now())) { "이체 일자는 현재 일자보다 이전이어야 합니다." } } + + fun isMyHistory(number: AccountNumber) = source == number || target == number } diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt new file mode 100644 index 0000000..ae9d462 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt @@ -0,0 +1,49 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.api.matcher.MatcherOperator +import com.navercorp.fixturemonkey.api.property.PropertyNameResolver +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.core.spec.style.FreeSpec +import java.time.LocalDateTime + +class AccountTest : FreeSpec({ + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + + fun transferHistories(myAccount: AccountNumber): TransferHistories { + val 계좌_과거_이력 = TransferHistories(listOf()) + for (i in 0..10) { + 계좌_과거_이력.addHistory( + fixtureMonkey.giveMeBuilder() + .set("source", myAccount) + .sample() + ) + 계좌_과거_이력.addHistory( + fixtureMonkey.giveMeBuilder() + .set("target", myAccount) + .sample() + ) + } + return 계좌_과거_이력 + } + + "10번 계좌 생성 중" - { + val 내_계좌 = fixtureMonkey.giveMeBuilder().sample() + val 계좌_과거_이력 = transferHistories(내_계좌) + for (i in 0..10) { + "$i 번째 계좌를 생성한다." { + val giveMeBuilder = fixtureMonkey.giveMeBuilder() + .set("number", 내_계좌) + .set("transferHistories", 계좌_과거_이력) + println(giveMeBuilder.sample()) + } + } + } +}) diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt index ab6a669..ce9daf7 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt @@ -2,11 +2,14 @@ package com.example.estdelivery.domain import com.navercorp.fixturemonkey.FixtureMonkey import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.api.matcher.MatcherOperator +import com.navercorp.fixturemonkey.api.property.PropertyNameResolver import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin import com.navercorp.fixturemonkey.kotlin.KotlinPlugin import com.navercorp.fixturemonkey.kotlin.giveMeBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe class TransferHistoriesTest : FreeSpec({ val fixtureMonkey = FixtureMonkey.builder() @@ -47,4 +50,25 @@ class TransferHistoriesTest : FreeSpec({ } } } + + "자신의 계좌를 확인할 때" - { + "경계값 - 비어있어도 자신의 계좌이다." { + val histories = TransferHistories(listOf()) + val number = fixtureMonkey.giveMeBuilder().sample() + histories.ensureMyHistories(number) shouldBe true + } + + "이력으로 자신의 계좌를 확인할 수 있다." { + val sourceAccountNumber = fixtureMonkey.giveMeBuilder().sample() + val histories = TransferHistories(listOf()) + for (i in 0..100) { + val transferHistory = fixtureMonkey.giveMeBuilder() + .set("source", sourceAccountNumber) + .sample() + histories.addHistory(transferHistory) + } + histories.ensureMyHistories(sourceAccountNumber) shouldBe true + } + } + }) From a6def22a66c52962566efa28ae407f4982af140b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:04:27 +0900 Subject: [PATCH 11/32] =?UTF-8?q?test=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/domain/AccountNumberTest.kt | 55 +++++++++++++------ .../example/estdelivery/domain/AccountTest.kt | 10 ++-- .../example/estdelivery/domain/MoneyTest.kt | 33 +++++++---- .../estdelivery/domain/TransferHistoryTest.kt | 4 +- 4 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt index 385d1a3..9ba23d6 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt @@ -6,33 +6,52 @@ import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPl import com.navercorp.fixturemonkey.kotlin.KotlinPlugin import com.navercorp.fixturemonkey.kotlin.giveMeBuilder import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow +import io.kotest.assertions.throwables.shouldThrowAny import io.kotest.core.spec.style.FreeSpec -import io.kotest.matchers.shouldBe +import net.jqwik.api.Arbitraries class AccountNumberTest : FreeSpec({ + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() - "임의 번호를 생성해" - { - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() + "계좌 번호를 생성 할 때" - { + "10자리 임의 번호를 생성해" - { + for (i in 0..300) { + "$i 번째 계좌 번호를 생성한다." { + shouldNotThrow { + fixtureMonkey.giveMeBuilder().sample() + } + } + } + } + + "경계값 - 계좌번호는 10자리 미만인" - { + val arbitrarily = Arbitraries.strings().numeric().ofMinLength(0).ofMaxLength(9) - for (i in 0..300) { - "$i 번째 계좌 번호를 생성한다." { - shouldNotThrow { - fixtureMonkey.giveMeBuilder().sample() + for (i in 0..100) { + val number = arbitrarily.sample() + "${number}로 생성하면 예외가 발생한다." { + shouldThrowAny { + fixtureMonkey.giveMeBuilder().set("accountNumber", number).sample() + } } } } - } - "계좌번호는 10자리가 아니면 예외가 발생한다." { - val accountNumber = "123456789" - val exception = shouldThrow { - AccountNumber(accountNumber) + "경계값 - 계좌번호가 10자리 초과인." - { + val arbitrarily = Arbitraries.strings().numeric().ofMinLength(11).ofMaxLength(20) + + for (i in 0..100) { + val number = arbitrarily.sample() + "${number}로 생성하면 예외가 발생한다." { + shouldThrowAny { + fixtureMonkey.giveMeBuilder().set("accountNumber", number).sample() + } + } + } } - exception.message shouldBe "계좌번호는 10자리여야 합니다." } }) diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt index ae9d462..0ebc9a6 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt @@ -7,6 +7,7 @@ import com.navercorp.fixturemonkey.api.property.PropertyNameResolver import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin import com.navercorp.fixturemonkey.kotlin.KotlinPlugin import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime @@ -39,10 +40,11 @@ class AccountTest : FreeSpec({ val 계좌_과거_이력 = transferHistories(내_계좌) for (i in 0..10) { "$i 번째 계좌를 생성한다." { - val giveMeBuilder = fixtureMonkey.giveMeBuilder() - .set("number", 내_계좌) - .set("transferHistories", 계좌_과거_이력) - println(giveMeBuilder.sample()) + shouldNotThrow { + fixtureMonkey.giveMeBuilder() + .set("number", 내_계좌) + .set("transferHistories", 계좌_과거_이력) + } } } } diff --git a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt index 8a55e31..7e55bd1 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt @@ -7,29 +7,38 @@ import com.navercorp.fixturemonkey.kotlin.KotlinPlugin import com.navercorp.fixturemonkey.kotlin.giveMeBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.assertions.throwables.shouldThrow +import io.kotest.assertions.throwables.shouldThrowAny import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe +import net.jqwik.api.Arbitraries import java.math.BigInteger class MoneyTest : FreeSpec({ - "0이상의 숫자를 넣어" - { - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + "0이상의 숫자를 넣어" - { for (i in 0..300) { "$i 번째 금액을 생성한다." { - val giveMeBuilder = fixtureMonkey.giveMeBuilder() - shouldNotThrow { giveMeBuilder.sample() } + val money = fixtureMonkey.giveMeBuilder() + shouldNotThrow { money.sample() } } } } - "금액은 0원 이상이어야 한다." { - shouldThrow { - Money(BigInteger.valueOf(-1)) - }.message shouldBe "금액은 0원 이상이어야 합니다." + "금액은 0원 이상이어야 한다." - { + val money = fixtureMonkey.giveMeBuilder() + .set("amount", Arbitraries.bigIntegers().lessOrEqual(BigInteger.valueOf(-1L))) + + for (i in 0..200) { + "$i 번째 금액을 생성한다." { + shouldThrowAny { + money.sample() + } + } + } } }) diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt index a74607b..29983a4 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt @@ -18,7 +18,7 @@ class TransferHistoryTest : FreeSpec({ .plugin(JakartaValidationPlugin()) .build() - "300 번 중" - { + "300번 중" - { for (i in 0..300) { "$i 번째 송금 내역을 생성한다." { println(fixtureMonkey.giveMeBuilder().sample()) @@ -26,7 +26,7 @@ class TransferHistoryTest : FreeSpec({ } } - "입급 계좌와 출급 계좌가 같을 수 없다." { + "입금 계좌와 출금 계좌가 같을 수 없다." { val sameAccountNumber = fixtureMonkey.giveMeBuilder().sample() val money = fixtureMonkey.giveMeBuilder().sample() From 073affbffd7dce1d164f5950ef5e60d6d089bc36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:25:36 +0900 Subject: [PATCH 12/32] =?UTF-8?q?feature=20:=20AccountTransaction=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/domain/AccountTransaction.kt | 15 ++++++++ .../domain/AccountTransactionTest.kt | 38 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt new file mode 100644 index 0000000..a0235de --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt @@ -0,0 +1,15 @@ +package com.example.estdelivery.domain + +import jakarta.validation.constraints.PastOrPresent +import java.time.LocalDateTime + +data class AccountTransaction( + val amount: Money, + val type: TransactionType, + @field:PastOrPresent + private val transactionDateTime: LocalDateTime, +) { + init { + require(transactionDateTime.isBefore(LocalDateTime.now())) { "거래 일자는 현재 시간보다 이전이어야 합니다." } + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt new file mode 100644 index 0000000..975e069 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt @@ -0,0 +1,38 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.core.spec.style.FreeSpec +import java.time.LocalDateTime + +class AccountTransactionTest : FreeSpec({ + val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + + "계좌 거래 내역을 생성한다." - { + for (i in 0..300) { + "$i 번째 거래 내역을 생성한다." { + shouldNotThrow { + fixtureMonkey.giveMeBuilder() + .sample() + } + } + } + } + + "계좌 거래 일자가 미래일 수 없다." { + val futureDate = LocalDateTime.now().plusDays(1) + shouldNotThrow { + fixtureMonkey.giveMeBuilder() + .set("transactionTime", futureDate) + .sample() + } + } +}) From 4ba8fc51f5715d5bcffdf5130d3fafa5d6b1162f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:33:25 +0900 Subject: [PATCH 13/32] =?UTF-8?q?refactor=20:=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/domain/Account.kt | 12 +++++++---- .../estdelivery/domain/AccountNumber.kt | 6 +----- .../estdelivery/domain/AccountTransaction.kt | 6 +----- .../com/example/estdelivery/domain/Money.kt | 12 +++++++++++ .../estdelivery/domain/TransferHistories.kt | 9 -------- .../estdelivery/domain/TransferHistory.kt | 3 --- .../domain/TransferHistoriesTest.kt | 21 ------------------- .../estdelivery/domain/TransferHistoryTest.kt | 11 +++------- 8 files changed, 25 insertions(+), 55 deletions(-) diff --git a/src/main/kotlin/com/example/estdelivery/domain/Account.kt b/src/main/kotlin/com/example/estdelivery/domain/Account.kt index 75ec1e2..b047b73 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Account.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Account.kt @@ -5,14 +5,14 @@ import java.time.LocalDateTime class Account( private val number: AccountNumber, - private val balance: Money, private val transferHistories: TransferHistories, + private val transactions: AccountTransactions, @field:PastOrPresent private val createdDate: LocalDateTime, private val id: Long? = null ) { - init { - require(transferHistories.ensureMyHistories(number)) { "자신의 이력이 아닌 정보가 존재합니다." } + fun balance(): Money { + return transactions.balance() } override fun equals(other: Any?): Boolean { @@ -29,6 +29,10 @@ class Account( } override fun toString(): String { - return "Account(number=$number, balance=$balance, transferHistories=$transferHistories, createdDate=$createdDate, id=$id)" + return "Account(number=$number, balance=${balance()}, transferHistories=$transferHistories, createdDate=$createdDate, id=$id)" + } + + fun deposit(amount: Money, transactionTime: LocalDateTime) { + transactions.deposit(amount, transactionTime) } } diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt index af4369a..971f059 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountNumber.kt @@ -7,8 +7,4 @@ data class AccountNumber( @field:Size(min = 10, max = 10) @field:Pattern(regexp = "^[0-9]*$") private val accountNumber: String -) { - init { - require(accountNumber.length == 10) { "계좌번호는 10자리여야 합니다." } - } -} +) diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt index a0235de..e171474 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt @@ -8,8 +8,4 @@ data class AccountTransaction( val type: TransactionType, @field:PastOrPresent private val transactionDateTime: LocalDateTime, -) { - init { - require(transactionDateTime.isBefore(LocalDateTime.now())) { "거래 일자는 현재 시간보다 이전이어야 합니다." } - } -} +) diff --git a/src/main/kotlin/com/example/estdelivery/domain/Money.kt b/src/main/kotlin/com/example/estdelivery/domain/Money.kt index 6c6831e..244e2d6 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Money.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Money.kt @@ -10,4 +10,16 @@ data class Money( init { require(amount >= BigInteger.ZERO) { "금액은 0원 이상이어야 합니다." } } + + companion object { + val ZERO: Money = Money(BigInteger.ZERO) + } + + operator fun plus(amount: Money): Money { + return Money(this.amount.add(amount.amount)) + } + + operator fun minus(amount: Money): Money { + return Money(this.amount.subtract(amount.amount)) + } } diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt index ba90932..8bf2702 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt @@ -15,15 +15,6 @@ class TransferHistories( transferHistories = transferHistories - transferHistory } - fun ensureMyHistories(number: AccountNumber): Boolean { - for (transferHistory in transferHistories) { - if (transferHistory.isMyHistory(number).not()) { - return false - } - } - return true - } - override fun toString(): String { return "TransferHistories(transferHistories=$transferHistories)" } diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt index 3ae9c9e..ccad89e 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt @@ -12,8 +12,5 @@ data class TransferHistory( ) { init { require(source != target) { "출금 계좌와 입금 계좌는 같을 수 없습니다." } - require(transferDate.isBefore(LocalDateTime.now())) { "이체 일자는 현재 일자보다 이전이어야 합니다." } } - - fun isMyHistory(number: AccountNumber) = source == number || target == number } diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt index ce9daf7..a6eb36c 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt @@ -50,25 +50,4 @@ class TransferHistoriesTest : FreeSpec({ } } } - - "자신의 계좌를 확인할 때" - { - "경계값 - 비어있어도 자신의 계좌이다." { - val histories = TransferHistories(listOf()) - val number = fixtureMonkey.giveMeBuilder().sample() - histories.ensureMyHistories(number) shouldBe true - } - - "이력으로 자신의 계좌를 확인할 수 있다." { - val sourceAccountNumber = fixtureMonkey.giveMeBuilder().sample() - val histories = TransferHistories(listOf()) - for (i in 0..100) { - val transferHistory = fixtureMonkey.giveMeBuilder() - .set("source", sourceAccountNumber) - .sample() - histories.addHistory(transferHistory) - } - histories.ensureMyHistories(sourceAccountNumber) shouldBe true - } - } - }) diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt index 29983a4..62afe94 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt @@ -37,15 +37,10 @@ class TransferHistoryTest : FreeSpec({ "이체 일자는 현재 시간보다 이전이어야 한다." { val futureDateTime = LocalDateTime.now().plusDays(1) - val money = fixtureMonkey.giveMeBuilder().sample() - shouldThrow { - TransferHistory( - fixtureMonkey.giveMeBuilder().sample(), - fixtureMonkey.giveMeBuilder().sample(), - money, - futureDateTime - ) + fixtureMonkey.giveMeBuilder() + .set("transferDate", futureDateTime) + .sample() } } }) From 4e455274a589d9e7bda01393ff6bc00b75bd5f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:43:10 +0900 Subject: [PATCH 14/32] =?UTF-8?q?test=20:=20FixtureMonkeyUtil=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/estdelivery/domain/AccountTransaction.kt | 2 +- .../kotlin/com/example/estdelivery/domain/Money.kt | 4 ++++ .../example/estdelivery/domain/AccountNumberTest.kt | 6 ------ .../com/example/estdelivery/domain/AccountTest.kt | 6 ------ .../estdelivery/domain/AccountTransactionTest.kt | 6 ------ .../example/estdelivery/domain/FixtureMonkeyUtil.kt | 12 ++++++++++++ .../com/example/estdelivery/domain/MoneyTest.kt | 6 ------ .../estdelivery/domain/TransferHistoriesTest.kt | 6 ------ .../estdelivery/domain/TransferHistoryTest.kt | 6 ------ 9 files changed, 17 insertions(+), 37 deletions(-) create mode 100644 src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt index e171474..eadef0f 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt @@ -7,5 +7,5 @@ data class AccountTransaction( val amount: Money, val type: TransactionType, @field:PastOrPresent - private val transactionDateTime: LocalDateTime, + val transactionDateTime: LocalDateTime, ) diff --git a/src/main/kotlin/com/example/estdelivery/domain/Money.kt b/src/main/kotlin/com/example/estdelivery/domain/Money.kt index 244e2d6..09ca449 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Money.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Money.kt @@ -22,4 +22,8 @@ data class Money( operator fun minus(amount: Money): Money { return Money(this.amount.subtract(amount.amount)) } + + operator fun compareTo(amount: Money): Int { + return this.amount.compareTo(amount.amount) + } } diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt index 9ba23d6..989fd21 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt @@ -11,12 +11,6 @@ import io.kotest.core.spec.style.FreeSpec import net.jqwik.api.Arbitraries class AccountNumberTest : FreeSpec({ - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() - "계좌 번호를 생성 할 때" - { "10자리 임의 번호를 생성해" - { for (i in 0..300) { diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt index 0ebc9a6..0e11bfc 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt @@ -12,12 +12,6 @@ import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime class AccountTest : FreeSpec({ - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() - fun transferHistories(myAccount: AccountNumber): TransferHistories { val 계좌_과거_이력 = TransferHistories(listOf()) for (i in 0..10) { diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt index 975e069..3c75df4 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt @@ -10,12 +10,6 @@ import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime class AccountTransactionTest : FreeSpec({ - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() - "계좌 거래 내역을 생성한다." - { for (i in 0..300) { "$i 번째 거래 내역을 생성한다." { diff --git a/src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt b/src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt new file mode 100644 index 0000000..a6ed146 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt @@ -0,0 +1,12 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin + +val fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() diff --git a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt index 7e55bd1..c4f5a31 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt @@ -14,12 +14,6 @@ import net.jqwik.api.Arbitraries import java.math.BigInteger class MoneyTest : FreeSpec({ - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() - "0이상의 숫자를 넣어" - { for (i in 0..300) { "$i 번째 금액을 생성한다." { diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt index a6eb36c..e1445d0 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt @@ -12,12 +12,6 @@ import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe class TransferHistoriesTest : FreeSpec({ - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() - "이체 내역을 생성한다." { val list = fixtureMonkey.giveMeBuilder>().sample() diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt index 62afe94..7e88a7d 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt @@ -12,12 +12,6 @@ import io.kotest.matchers.shouldBe import java.time.LocalDateTime class TransferHistoryTest : FreeSpec({ - val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() - "300번 중" - { for (i in 0..300) { "$i 번째 송금 내역을 생성한다." { From 8dd5047160218000cd4cec1b4e65977ff2c1927a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:46:59 +0900 Subject: [PATCH 15/32] =?UTF-8?q?feature=20:=20Deposit=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/domain/AccountTransactions.kt | 26 ++++++++++++++++ .../com/example/estdelivery/domain/Deposit.kt | 13 ++++++++ .../estdelivery/domain/TransactionType.kt | 6 ++++ .../domain/AccountTransactionsTest.kt | 31 +++++++++++++++++++ .../example/estdelivery/domain/DepositTest.kt | 29 +++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt create mode 100644 src/main/kotlin/com/example/estdelivery/domain/Deposit.kt create mode 100644 src/main/kotlin/com/example/estdelivery/domain/TransactionType.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt new file mode 100644 index 0000000..68bfc8b --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt @@ -0,0 +1,26 @@ +package com.example.estdelivery.domain + +import java.time.LocalDateTime + +class AccountTransactions( + private var accountTransactions: List +) { + fun deposit(amount: Money, transactionTime: LocalDateTime) { + accountTransactions = accountTransactions + AccountTransaction(amount, TransactionType.DEPOSIT, transactionTime) + } + + fun withdraw(amount: Money, transactionTime: LocalDateTime) { + accountTransactions = + accountTransactions + AccountTransaction(amount, TransactionType.WITHDRAWAL, transactionTime) + } + + fun balance(): Money { + return accountTransactions.sortedBy { it.transactionDateTime } + .fold(Money.ZERO) { acc, accountTransaction -> + when (accountTransaction.type) { + TransactionType.DEPOSIT -> acc + accountTransaction.amount + TransactionType.WITHDRAWAL -> acc - accountTransaction.amount + } + } + } +} diff --git a/src/main/kotlin/com/example/estdelivery/domain/Deposit.kt b/src/main/kotlin/com/example/estdelivery/domain/Deposit.kt new file mode 100644 index 0000000..b5f3659 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/Deposit.kt @@ -0,0 +1,13 @@ +package com.example.estdelivery.domain + +import java.time.LocalDateTime + +class Deposit( + private val account: Account, + private val amount: Money, + private val transactionTime: LocalDateTime +) { + fun deposit() { + account.deposit(amount, transactionTime) + } +} diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransactionType.kt b/src/main/kotlin/com/example/estdelivery/domain/TransactionType.kt new file mode 100644 index 0000000..8b1eb40 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/TransactionType.kt @@ -0,0 +1,6 @@ +package com.example.estdelivery.domain + +enum class TransactionType { + WITHDRAWAL, + DEPOSIT +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt new file mode 100644 index 0000000..ab65795 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt @@ -0,0 +1,31 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.core.spec.style.FreeSpec +import java.time.LocalDateTime + +class AccountTransactionsTest : FreeSpec({ + val accountTransactions = fixtureMonkey.giveMeBuilder().sample() + val money = fixtureMonkey.giveMeBuilder().sample() + + "돈 입금 기록을 추가한다." { + shouldNotThrow { + accountTransactions.deposit(money, LocalDateTime.now()) + } + } + + "돈 출금 기록을 추가한다." { + shouldNotThrow { + accountTransactions.withdraw(money, LocalDateTime.now()) + } + } + + "잔액을 조회한다." { + println(accountTransactions.balance()) + } +}) diff --git a/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt b/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt new file mode 100644 index 0000000..458307c --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt @@ -0,0 +1,29 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import java.time.LocalDateTime + +class DepositTest : FreeSpec({ + "입금하는데, " - { + for (i in 0..300) { + // given + val account = fixtureMonkey.giveMeBuilder() + .set("transactions", AccountTransactions(listOf())) + .sample() + var beforeBalance = account.balance() + "무려 $i 번째 입금이다." { + val money = fixtureMonkey.giveMeBuilder().sample() + val deposit = Deposit(account, money, LocalDateTime.now()) + + // when + deposit.deposit() + + // then + account.balance() shouldBe beforeBalance + money + beforeBalance = account.balance() + } + } + } +}) From 0728d6fbc439841fab80ce42eca5536c7bac9d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:52:44 +0900 Subject: [PATCH 16/32] =?UTF-8?q?feature=20:=20Withdrawal=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/domain/Account.kt | 4 ++ .../example/estdelivery/domain/Withdrawal.kt | 17 +++++++ .../estdelivery/domain/WithdrawalTest.kt | 49 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/Withdrawal.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/Account.kt b/src/main/kotlin/com/example/estdelivery/domain/Account.kt index b047b73..ac173cb 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Account.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Account.kt @@ -35,4 +35,8 @@ class Account( fun deposit(amount: Money, transactionTime: LocalDateTime) { transactions.deposit(amount, transactionTime) } + + fun withdraw(amount: Money, transactionTime: LocalDateTime) { + transactions.withdraw(amount, transactionTime) + } } diff --git a/src/main/kotlin/com/example/estdelivery/domain/Withdrawal.kt b/src/main/kotlin/com/example/estdelivery/domain/Withdrawal.kt new file mode 100644 index 0000000..c7cbdfd --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/Withdrawal.kt @@ -0,0 +1,17 @@ +package com.example.estdelivery.domain + +import java.time.LocalDateTime + +class Withdrawal( + private val account: Account, + private val amount: Money, + private val transactionTime: LocalDateTime +) { + init { + require(account.balance() >= amount) { "잔액이 부족합니다." } + } + + fun withdraw() { + account.withdraw(amount, transactionTime) + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt b/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt new file mode 100644 index 0000000..7a7d029 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt @@ -0,0 +1,49 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import net.jqwik.api.Arbitraries +import java.math.BigInteger +import java.time.LocalDateTime + +class WithdrawalTest : FreeSpec({ + + "출금하는데, " - { + // given + val account = fixtureMonkey.giveMeBuilder() + .set("transactions", AccountTransactions(listOf())) + .sample() + account.deposit(Money(6_000_000.toBigInteger()), LocalDateTime.now()) + + var beforeBalance = account.balance() + for (i in 0..300) { + "무려 $i 번째 출금이다." { + val money = fixtureMonkey.giveMeBuilder() + .set("amount", Arbitraries.bigIntegers().between(BigInteger.ZERO, 20_000.toBigInteger())) + .sample() + val withdrawal = Withdrawal(account, money, LocalDateTime.now()) + + // when + withdrawal.withdraw() + + // then + account.balance() shouldBe beforeBalance - money + beforeBalance = account.balance() + } + } + } + + "출금하는데 잔액이 부족하면 예외가 발생한다." { + val account = fixtureMonkey.giveMeBuilder() + .set("transactions", AccountTransactions(listOf())) + .sample() + val money = fixtureMonkey.giveMeBuilder().sample() + + shouldThrow { + Withdrawal(account, money, LocalDateTime.now()) + } + } + +}) From d28ac463bafaf7ec38ea3a3b01f23631118563d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:57:02 +0900 Subject: [PATCH 17/32] =?UTF-8?q?feature=20:=20Transfer=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/estdelivery/domain/Transfer.kt | 15 +++++++ .../estdelivery/domain/TransferTest.kt | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/domain/Transfer.kt create mode 100644 src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/domain/Transfer.kt b/src/main/kotlin/com/example/estdelivery/domain/Transfer.kt new file mode 100644 index 0000000..6f70298 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/domain/Transfer.kt @@ -0,0 +1,15 @@ +package com.example.estdelivery.domain + +import java.time.LocalDateTime + +class Transfer( + private val source: Account, + private val target: Account, + private val amount: Money, + private val transactionTime: LocalDateTime +) { + fun transfer() { + Withdrawal(source, amount, transactionTime).withdraw() + Deposit(target, amount, transactionTime).deposit() + } +} diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt new file mode 100644 index 0000000..535d153 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt @@ -0,0 +1,41 @@ +package com.example.estdelivery.domain + +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import net.jqwik.api.Arbitraries +import java.math.BigInteger +import java.time.LocalDateTime + +class TransferTest : FreeSpec({ + "이체하는데, " - { + // given + val source = fixtureMonkey.giveMeBuilder() + .set("transactions", AccountTransactions(listOf())) + .sample() + val target = fixtureMonkey.giveMeBuilder() + .set("transactions", AccountTransactions(listOf())) + .sample() + + source.deposit(Money(6_000_000.toBigInteger()), LocalDateTime.now()) + var beforeSourceBalance = source.balance() + var beforeTargetBalance = target.balance() + for (i in 0..300) { + "무려 $i 번째 이체이다." { + val money = fixtureMonkey.giveMeBuilder() + .set("amount", Arbitraries.bigIntegers().between(BigInteger.ZERO, 20_000.toBigInteger())) + .sample() + val transfer = Transfer(source, target, money, LocalDateTime.now()) + + // when + transfer.transfer() + + // then + source.balance() shouldBe beforeSourceBalance - money + target.balance() shouldBe beforeTargetBalance + money + beforeSourceBalance = source.balance() + beforeTargetBalance = target.balance() + } + } + } +}) From 861b5e64b48d3d6ba9f32cf39e33fca7ae5b26ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 01:14:04 +0900 Subject: [PATCH 18/32] =?UTF-8?q?chore=20:=20gitignore=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 --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 3d8b537..ff6bd83 100644 --- a/.gitignore +++ b/.gitignore @@ -146,4 +146,9 @@ gradle-app.setting .jqwik-database +# out package exclusion + +!src/main/kotlin/com/example/estdelivery/application/port/out +!src/test/kotlin/com/example/estdelivery/application/port/out + # End of https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,kotlin From 46c15ddaf3315251649f95cb46f8fb053de5b9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 08:04:42 +0900 Subject: [PATCH 19/32] =?UTF-8?q?feature=20:=20usecase=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/CreateAccountService.kt | 15 +++++++++++++++ .../estdelivery/application/DepositService.kt | 15 +++++++++++++++ .../estdelivery/application/TransferService.kt | 15 +++++++++++++++ .../estdelivery/application/WithdrawService.kt | 15 +++++++++++++++ .../application/port/in/CreateAccountUseCase.kt | 11 +++++++++++ .../application/port/in/DepositUseCase.kt | 11 +++++++++++ .../application/port/in/TransferUseCase.kt | 11 +++++++++++ .../application/port/in/WithdrawUseCase.kt | 12 ++++++++++++ .../port/in/command/CreateAccountCommand.kt | 5 +++++ .../application/port/in/command/DepositCommand.kt | 5 +++++ .../port/in/command/TransferCommand.kt | 5 +++++ .../port/in/command/WithdrawCommand.kt | 5 +++++ .../application/port/out/CreateAccountPort.kt | 4 ++++ .../application/port/out/LoadAccountPort.kt | 4 ++++ .../application/port/out/UpdateAccountPort.kt | 4 ++++ 15 files changed, 137 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/DepositService.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/TransferService.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt b/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt new file mode 100644 index 0000000..37ab65f --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt @@ -0,0 +1,15 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.application.port.`in`.CreateAccountUseCase +import com.example.estdelivery.application.port.`in`.command.CreateAccountCommand +import com.example.estdelivery.application.port.out.CreateAccountPort +import com.example.estdelivery.application.port.out.LoadAccountPort + +class CreateAccountService( + private val loadAccountPort: LoadAccountPort, + private val createAccountPort: CreateAccountPort +) : CreateAccountUseCase { + override fun createAccount(createAccountCommand: CreateAccountCommand) { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt new file mode 100644 index 0000000..54c22cd --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt @@ -0,0 +1,15 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.application.port.`in`.DepositUseCase +import com.example.estdelivery.application.port.`in`.command.DepositCommand +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort + +class DepositService( + private val loadAccountPort: LoadAccountPort, + private val updateAccountPort: UpdateAccountPort +) : DepositUseCase { + override fun deposit(depositCommand: DepositCommand) { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt new file mode 100644 index 0000000..38dbeab --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt @@ -0,0 +1,15 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.application.port.`in`.TransferUseCase +import com.example.estdelivery.application.port.`in`.command.TransferCommand +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort + +class TransferService( + private val loadAccountPort: LoadAccountPort, + private val updateAccountPort: UpdateAccountPort +) : TransferUseCase { + override fun transfer(transferCommand: TransferCommand) { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt new file mode 100644 index 0000000..e66587e --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt @@ -0,0 +1,15 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.application.port.`in`.WithdrawUseCase +import com.example.estdelivery.application.port.`in`.command.WithdrawCommand +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort + +class WithdrawService( + private val loadAccountPort: LoadAccountPort, + private val updateAccountPort: UpdateAccountPort +) : WithdrawUseCase { + override fun withdraw(withdrawCommand: WithdrawCommand) { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt new file mode 100644 index 0000000..6d07183 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt @@ -0,0 +1,11 @@ +package com.example.estdelivery.application.port.`in` + +import com.example.estdelivery.application.port.`in`.command.CreateAccountCommand + +interface CreateAccountUseCase { + /** + * 계좌를 생성한다. 생성되는 계좌는 고유하며 잔액은 0원이다. + * @param createAccountCommand + */ + fun createAccount(createAccountCommand: CreateAccountCommand) +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt new file mode 100644 index 0000000..9a559a3 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt @@ -0,0 +1,11 @@ +package com.example.estdelivery.application.port.`in` + +import com.example.estdelivery.application.port.`in`.command.DepositCommand + +interface DepositUseCase { + /** + * 계좌에 돈을 입금한다. + * @param depositCommand + */ + fun deposit(depositCommand: DepositCommand) +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt new file mode 100644 index 0000000..731755b --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt @@ -0,0 +1,11 @@ +package com.example.estdelivery.application.port.`in` + +import com.example.estdelivery.application.port.`in`.command.TransferCommand + +interface TransferUseCase { + /** + * 계좌 간 돈을 이체한다. 이체할 계좌 잔액은 이체할 금액보다 많아야 한다. + * @param transferCommand + */ + fun transfer(transferCommand: TransferCommand) +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt new file mode 100644 index 0000000..0896134 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt @@ -0,0 +1,12 @@ +package com.example.estdelivery.application.port.`in` + +import com.example.estdelivery.application.port.`in`.command.WithdrawCommand + +interface WithdrawUseCase { + /** + * 돈을 출금한다. 계좌 잔액은 출금 금액보다 많거나 같아야 한다. + * + * @param withdrawCommand 출금 명령 + */ + fun withdraw(withdrawCommand: WithdrawCommand) +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt new file mode 100644 index 0000000..dba4d3a --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt @@ -0,0 +1,5 @@ +package com.example.estdelivery.application.port.`in`.command + +class CreateAccountCommand { + +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt new file mode 100644 index 0000000..0e56fec --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt @@ -0,0 +1,5 @@ +package com.example.estdelivery.application.port.`in`.command + +class DepositCommand { + +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt new file mode 100644 index 0000000..02bbaa1 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt @@ -0,0 +1,5 @@ +package com.example.estdelivery.application.port.`in`.command + +class TransferCommand { + +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt new file mode 100644 index 0000000..98f2ec2 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt @@ -0,0 +1,5 @@ +package com.example.estdelivery.application.port.`in`.command + +class WithdrawCommand { + +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt new file mode 100644 index 0000000..7d8d1bc --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt @@ -0,0 +1,4 @@ +package com.example.estdelivery.application.port.out + +interface CreateAccountPort { +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt new file mode 100644 index 0000000..305377e --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt @@ -0,0 +1,4 @@ +package com.example.estdelivery.application.port.out + +class LoadAccountPort { +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt new file mode 100644 index 0000000..1570b44 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt @@ -0,0 +1,4 @@ +package com.example.estdelivery.application.port.out + +class UpdateAccountPort { +} From d9837e5247cdcf26ff3978e224a05ff36c8257e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:40:25 +0900 Subject: [PATCH 20/32] =?UTF-8?q?test=20:=20fixture=20monkey=20build=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EB=B2=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/port/out/LoadAccountPort.kt | 5 +++- .../application/port/out/UpdateAccountPort.kt | 2 +- .../estdelivery/domain/AccountTransactions.kt | 2 +- .../estdelivery/domain/TransferHistories.kt | 2 +- .../example/estdelivery/FixtureMonkeyUtil.kt | 30 +++++++++++++++++++ .../estdelivery/domain/AccountNumberTest.kt | 12 +++----- .../example/estdelivery/domain/AccountTest.kt | 20 +++++-------- .../domain/AccountTransactionTest.kt | 10 ++----- .../domain/AccountTransactionsTest.kt | 11 +++---- .../example/estdelivery/domain/DepositTest.kt | 7 +++-- .../estdelivery/domain/FixtureMonkeyUtil.kt | 12 -------- .../example/estdelivery/domain/MoneyTest.kt | 12 ++------ .../domain/TransferHistoriesTest.kt | 21 +++++-------- .../estdelivery/domain/TransferHistoryTest.kt | 18 +++++------ .../estdelivery/domain/TransferTest.kt | 9 +++--- .../estdelivery/domain/WithdrawalTest.kt | 11 +++---- 16 files changed, 88 insertions(+), 96 deletions(-) create mode 100644 src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt delete mode 100644 src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt index 305377e..406af8c 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt @@ -1,4 +1,7 @@ package com.example.estdelivery.application.port.out -class LoadAccountPort { +import com.example.estdelivery.domain.AccountNumber + +interface LoadAccountPort { + fun existsByAccountNumber(accountNumber: AccountNumber): Boolean } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt index 1570b44..7525090 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt @@ -1,4 +1,4 @@ package com.example.estdelivery.application.port.out -class UpdateAccountPort { +interface UpdateAccountPort { } diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt index 68bfc8b..de8da81 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt @@ -3,7 +3,7 @@ package com.example.estdelivery.domain import java.time.LocalDateTime class AccountTransactions( - private var accountTransactions: List + private var accountTransactions: List = listOf() ) { fun deposit(amount: Money, transactionTime: LocalDateTime) { accountTransactions = accountTransactions + AccountTransaction(amount, TransactionType.DEPOSIT, transactionTime) diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt index 8bf2702..24d58f9 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt @@ -1,7 +1,7 @@ package com.example.estdelivery.domain class TransferHistories( - private var transferHistories: List + private var transferHistories: List = listOf() ) { fun showHistories(): List { return transferHistories diff --git a/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt b/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt new file mode 100644 index 0000000..a3727c0 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt @@ -0,0 +1,30 @@ +package com.example.estdelivery + +import com.example.estdelivery.application.port.`in`.command.CreateAccountCommand +import com.example.estdelivery.domain.Account +import com.example.estdelivery.domain.AccountNumber +import com.example.estdelivery.domain.AccountTransaction +import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.domain.Money +import com.example.estdelivery.domain.TransferHistories +import com.example.estdelivery.domain.TransferHistory +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder + +private val fixtureMonkey: FixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) + .plugin(KotlinPlugin()) + .plugin(JakartaValidationPlugin()) + .build() + +fun accountCommandArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun moneyArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun accountArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun accountNumberArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun transferHistoryArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun transferHistoriesArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun accountTransactionArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun accountTransactionsArbitraryBuilder() = fixtureMonkey.giveMeBuilder() diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt index 989fd21..e235de0 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountNumberTest.kt @@ -1,10 +1,6 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.assertions.throwables.shouldThrowAny import io.kotest.core.spec.style.FreeSpec @@ -16,7 +12,7 @@ class AccountNumberTest : FreeSpec({ for (i in 0..300) { "$i 번째 계좌 번호를 생성한다." { shouldNotThrow { - fixtureMonkey.giveMeBuilder().sample() + accountNumberArbitraryBuilder().sample() } } } @@ -29,7 +25,7 @@ class AccountNumberTest : FreeSpec({ val number = arbitrarily.sample() "${number}로 생성하면 예외가 발생한다." { shouldThrowAny { - fixtureMonkey.giveMeBuilder().set("accountNumber", number).sample() + accountNumberArbitraryBuilder().set("accountNumber", number).sample() } } } @@ -42,7 +38,7 @@ class AccountNumberTest : FreeSpec({ val number = arbitrarily.sample() "${number}로 생성하면 예외가 발생한다." { shouldThrowAny { - fixtureMonkey.giveMeBuilder().set("accountNumber", number).sample() + accountNumberArbitraryBuilder().set("accountNumber", number).sample() } } } diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt index 0e11bfc..c72c684 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt @@ -1,27 +1,23 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.api.matcher.MatcherOperator -import com.navercorp.fixturemonkey.api.property.PropertyNameResolver -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder +import com.example.estdelivery.transferHistoryArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.core.spec.style.FreeSpec -import java.time.LocalDateTime + class AccountTest : FreeSpec({ fun transferHistories(myAccount: AccountNumber): TransferHistories { val 계좌_과거_이력 = TransferHistories(listOf()) for (i in 0..10) { 계좌_과거_이력.addHistory( - fixtureMonkey.giveMeBuilder() + transferHistoryArbitraryBuilder() .set("source", myAccount) .sample() ) 계좌_과거_이력.addHistory( - fixtureMonkey.giveMeBuilder() + transferHistoryArbitraryBuilder() .set("target", myAccount) .sample() ) @@ -30,12 +26,12 @@ class AccountTest : FreeSpec({ } "10번 계좌 생성 중" - { - val 내_계좌 = fixtureMonkey.giveMeBuilder().sample() + val 내_계좌 = accountNumberArbitraryBuilder().sample() val 계좌_과거_이력 = transferHistories(내_계좌) for (i in 0..10) { "$i 번째 계좌를 생성한다." { shouldNotThrow { - fixtureMonkey.giveMeBuilder() + accountArbitraryBuilder() .set("number", 내_계좌) .set("transferHistories", 계좌_과거_이력) } diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt index 3c75df4..5ee340b 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt @@ -1,10 +1,6 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountTransactionArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime @@ -14,7 +10,7 @@ class AccountTransactionTest : FreeSpec({ for (i in 0..300) { "$i 번째 거래 내역을 생성한다." { shouldNotThrow { - fixtureMonkey.giveMeBuilder() + accountTransactionArbitraryBuilder() .sample() } } @@ -24,7 +20,7 @@ class AccountTransactionTest : FreeSpec({ "계좌 거래 일자가 미래일 수 없다." { val futureDate = LocalDateTime.now().plusDays(1) shouldNotThrow { - fixtureMonkey.giveMeBuilder() + accountTransactionArbitraryBuilder() .set("transactionTime", futureDate) .sample() } diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt index ab65795..04ddbbc 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt @@ -1,17 +1,14 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountTransactionsArbitraryBuilder +import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime class AccountTransactionsTest : FreeSpec({ - val accountTransactions = fixtureMonkey.giveMeBuilder().sample() - val money = fixtureMonkey.giveMeBuilder().sample() + val money = moneyArbitraryBuilder().sample() + val accountTransactions = accountTransactionsArbitraryBuilder().sample() "돈 입금 기록을 추가한다." { shouldNotThrow { diff --git a/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt b/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt index 458307c..7dfb3ca 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/DepositTest.kt @@ -1,6 +1,7 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe import java.time.LocalDateTime @@ -9,12 +10,12 @@ class DepositTest : FreeSpec({ "입금하는데, " - { for (i in 0..300) { // given - val account = fixtureMonkey.giveMeBuilder() + val account = accountArbitraryBuilder() .set("transactions", AccountTransactions(listOf())) .sample() var beforeBalance = account.balance() "무려 $i 번째 입금이다." { - val money = fixtureMonkey.giveMeBuilder().sample() + val money = moneyArbitraryBuilder().sample() val deposit = Deposit(account, money, LocalDateTime.now()) // when diff --git a/src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt b/src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt deleted file mode 100644 index a6ed146..0000000 --- a/src/test/kotlin/com/example/estdelivery/domain/FixtureMonkeyUtil.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.estdelivery.domain - -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin - -val fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) - .plugin(KotlinPlugin()) - .plugin(JakartaValidationPlugin()) - .build() diff --git a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt index c4f5a31..fde04ea 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/MoneyTest.kt @@ -1,15 +1,9 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow import io.kotest.assertions.throwables.shouldThrowAny import io.kotest.core.spec.style.FreeSpec -import io.kotest.matchers.shouldBe import net.jqwik.api.Arbitraries import java.math.BigInteger @@ -17,14 +11,14 @@ class MoneyTest : FreeSpec({ "0이상의 숫자를 넣어" - { for (i in 0..300) { "$i 번째 금액을 생성한다." { - val money = fixtureMonkey.giveMeBuilder() + val money = moneyArbitraryBuilder() shouldNotThrow { money.sample() } } } } "금액은 0원 이상이어야 한다." - { - val money = fixtureMonkey.giveMeBuilder() + val money = moneyArbitraryBuilder() .set("amount", Arbitraries.bigIntegers().lessOrEqual(BigInteger.valueOf(-1L))) for (i in 0..200) { diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt index e1445d0..a552c03 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoriesTest.kt @@ -1,36 +1,29 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.api.matcher.MatcherOperator -import com.navercorp.fixturemonkey.api.property.PropertyNameResolver -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.transferHistoriesArbitraryBuilder +import com.example.estdelivery.transferHistoryArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.core.spec.style.FreeSpec -import io.kotest.matchers.shouldBe + class TransferHistoriesTest : FreeSpec({ "이체 내역을 생성한다." { - val list = fixtureMonkey.giveMeBuilder>().sample() - shouldNotThrow { - TransferHistories(list) + transferHistoriesArbitraryBuilder().sample() } } "이체 내역을 조회한다." { - val histories = fixtureMonkey.giveMeBuilder().sample() + val histories = transferHistoriesArbitraryBuilder().sample() shouldNotThrow { histories.showHistories() } } "이체 내역을 추가할 때" - { - val histories = fixtureMonkey.giveMeBuilder().sample() + val histories = transferHistoriesArbitraryBuilder().sample() for (i in 0..100) { - val transferHistory = fixtureMonkey.giveMeBuilder().sample() + val transferHistory = transferHistoryArbitraryBuilder().sample() "$i 번째 이력을 추가한다." { shouldNotThrow { histories.addHistory(transferHistory) diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt index 7e88a7d..f41ad6e 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt @@ -1,28 +1,24 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.FixtureMonkey -import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector -import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin -import com.navercorp.fixturemonkey.kotlin.KotlinPlugin -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder +import com.example.estdelivery.moneyArbitraryBuilder +import com.example.estdelivery.transferHistoryArbitraryBuilder import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FreeSpec -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe import java.time.LocalDateTime class TransferHistoryTest : FreeSpec({ "300번 중" - { for (i in 0..300) { "$i 번째 송금 내역을 생성한다." { - println(fixtureMonkey.giveMeBuilder().sample()) + println(transferHistoryArbitraryBuilder().sample()) } } } "입금 계좌와 출금 계좌가 같을 수 없다." { - val sameAccountNumber = fixtureMonkey.giveMeBuilder().sample() - val money = fixtureMonkey.giveMeBuilder().sample() + val sameAccountNumber = accountNumberArbitraryBuilder().sample() + val money = moneyArbitraryBuilder().sample() shouldThrow { TransferHistory(sameAccountNumber, sameAccountNumber, money, LocalDateTime.now()) @@ -32,7 +28,7 @@ class TransferHistoryTest : FreeSpec({ "이체 일자는 현재 시간보다 이전이어야 한다." { val futureDateTime = LocalDateTime.now().plusDays(1) shouldThrow { - fixtureMonkey.giveMeBuilder() + transferHistoryArbitraryBuilder() .set("transferDate", futureDateTime) .sample() } diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt index 535d153..f869c59 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferTest.kt @@ -1,6 +1,7 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe import net.jqwik.api.Arbitraries @@ -10,10 +11,10 @@ import java.time.LocalDateTime class TransferTest : FreeSpec({ "이체하는데, " - { // given - val source = fixtureMonkey.giveMeBuilder() + val source = accountArbitraryBuilder() .set("transactions", AccountTransactions(listOf())) .sample() - val target = fixtureMonkey.giveMeBuilder() + val target = accountArbitraryBuilder() .set("transactions", AccountTransactions(listOf())) .sample() @@ -22,7 +23,7 @@ class TransferTest : FreeSpec({ var beforeTargetBalance = target.balance() for (i in 0..300) { "무려 $i 번째 이체이다." { - val money = fixtureMonkey.giveMeBuilder() + val money = moneyArbitraryBuilder() .set("amount", Arbitraries.bigIntegers().between(BigInteger.ZERO, 20_000.toBigInteger())) .sample() val transfer = Transfer(source, target, money, LocalDateTime.now()) diff --git a/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt b/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt index 7a7d029..db53db7 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/WithdrawalTest.kt @@ -1,6 +1,7 @@ package com.example.estdelivery.domain -import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe @@ -12,7 +13,7 @@ class WithdrawalTest : FreeSpec({ "출금하는데, " - { // given - val account = fixtureMonkey.giveMeBuilder() + val account = accountArbitraryBuilder() .set("transactions", AccountTransactions(listOf())) .sample() account.deposit(Money(6_000_000.toBigInteger()), LocalDateTime.now()) @@ -20,7 +21,7 @@ class WithdrawalTest : FreeSpec({ var beforeBalance = account.balance() for (i in 0..300) { "무려 $i 번째 출금이다." { - val money = fixtureMonkey.giveMeBuilder() + val money = moneyArbitraryBuilder() .set("amount", Arbitraries.bigIntegers().between(BigInteger.ZERO, 20_000.toBigInteger())) .sample() val withdrawal = Withdrawal(account, money, LocalDateTime.now()) @@ -36,10 +37,10 @@ class WithdrawalTest : FreeSpec({ } "출금하는데 잔액이 부족하면 예외가 발생한다." { - val account = fixtureMonkey.giveMeBuilder() + val account = accountArbitraryBuilder() .set("transactions", AccountTransactions(listOf())) .sample() - val money = fixtureMonkey.giveMeBuilder().sample() + val money = moneyArbitraryBuilder().sample() shouldThrow { Withdrawal(account, money, LocalDateTime.now()) From 000aecffc01df71f4d9d4f6b2bff115e2f49e05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:18:51 +0900 Subject: [PATCH 21/32] =?UTF-8?q?chore=20:=20mockk=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index 2ff49b8..b13c770 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { testImplementation("io.kotest", "kotest-runner-junit5", "5.4.0") testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter-kotlin:1.0.13") testImplementation("com.navercorp.fixturemonkey:fixture-monkey-jakarta-validation:1.0.0") + testImplementation("io.mockk:mockk:1.13.9") } tasks.withType { From c47b35568b91ea20cfb2a40891e82bb7783ce25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:19:11 +0900 Subject: [PATCH 22/32] =?UTF-8?q?feature=20:=20CreateAccountService=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/CreateAccountService.kt | 20 ++++++++--- .../port/in/command/CreateAccountCommand.kt | 8 +++-- .../application/port/out/CreateAccountPort.kt | 3 ++ .../port/out/GenerateAccountNumberPort.kt | 7 ++++ .../application/CreateAccountServiceTest.kt | 36 +++++++++++++++++++ 5 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/GenerateAccountNumberPort.kt create mode 100644 src/test/kotlin/com/example/estdelivery/application/CreateAccountServiceTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt b/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt index 37ab65f..9064294 100644 --- a/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt @@ -3,13 +3,23 @@ package com.example.estdelivery.application import com.example.estdelivery.application.port.`in`.CreateAccountUseCase import com.example.estdelivery.application.port.`in`.command.CreateAccountCommand import com.example.estdelivery.application.port.out.CreateAccountPort -import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.GenerateAccountNumberPort +import com.example.estdelivery.domain.Account +import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.domain.TransferHistories class CreateAccountService( - private val loadAccountPort: LoadAccountPort, - private val createAccountPort: CreateAccountPort + private val createAccountPort: CreateAccountPort, + private val generateAccountNumber: GenerateAccountNumberPort, ) : CreateAccountUseCase { - override fun createAccount(createAccountCommand: CreateAccountCommand) { - TODO("Not yet implemented") + /** + * 1. 계좌를 생성한다. + * 2. 계좌 정보를 저장한다. + */ + override fun createAccount(command: CreateAccountCommand) { + val accountNumber = generateAccountNumber.generate() + val newAccount = + Account(accountNumber, TransferHistories(), AccountTransactions(), command.createTime) + createAccountPort.create(newAccount) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt index dba4d3a..08330b7 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/CreateAccountCommand.kt @@ -1,5 +1,9 @@ package com.example.estdelivery.application.port.`in`.command -class CreateAccountCommand { +import jakarta.validation.constraints.PastOrPresent +import java.time.LocalDateTime -} +data class CreateAccountCommand( + @field:PastOrPresent + val createTime: LocalDateTime +) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt index 7d8d1bc..3ae09bb 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt @@ -1,4 +1,7 @@ package com.example.estdelivery.application.port.out +import com.example.estdelivery.domain.Account + interface CreateAccountPort { + fun create(newAccount: Account) } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/GenerateAccountNumberPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/GenerateAccountNumberPort.kt new file mode 100644 index 0000000..52889f3 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/GenerateAccountNumberPort.kt @@ -0,0 +1,7 @@ +package com.example.estdelivery.application.port.out + +import com.example.estdelivery.domain.AccountNumber + +interface GenerateAccountNumberPort { + fun generate(): AccountNumber +} diff --git a/src/test/kotlin/com/example/estdelivery/application/CreateAccountServiceTest.kt b/src/test/kotlin/com/example/estdelivery/application/CreateAccountServiceTest.kt new file mode 100644 index 0000000..04c7444 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/application/CreateAccountServiceTest.kt @@ -0,0 +1,36 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.accountCommandArbitraryBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder +import com.example.estdelivery.application.port.out.CreateAccountPort +import com.example.estdelivery.application.port.out.GenerateAccountNumberPort +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.core.spec.style.FreeSpec +import io.mockk.every +import io.mockk.mockk + +class CreateAccountServiceTest : FreeSpec({ + + lateinit var createAccountPort: CreateAccountPort + lateinit var generateAccountNumberPort: GenerateAccountNumberPort + lateinit var createAccountService: CreateAccountService + + beforeTest { + createAccountPort = mockk() + generateAccountNumberPort = mockk() + createAccountService = CreateAccountService(createAccountPort, generateAccountNumberPort) + } + + "계좌를 생성한다." { + val accountNumber = accountNumberArbitraryBuilder().sample() + val accountCommand = accountCommandArbitraryBuilder().sample() + + every { generateAccountNumberPort.generate() } returns accountNumber + every { createAccountPort.create(any()) } returns Unit + + // then + shouldNotThrowAny { + createAccountService.createAccount(accountCommand) + } + } +}) From f8c63e6469ecc8a87976e645f5e899db2a047c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:39:49 +0900 Subject: [PATCH 23/32] =?UTF-8?q?feature=20:=20DepositService=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../estdelivery/application/DepositService.kt | 15 +++++- .../application/port/in/DepositUseCase.kt | 4 +- .../port/in/command/DepositCommand.kt | 12 ++++- .../application/port/out/LoadAccountPort.kt | 2 + .../application/port/out/UpdateAccountPort.kt | 3 ++ .../example/estdelivery/FixtureMonkeyUtil.kt | 2 + .../application/DepositServiceTest.kt | 47 +++++++++++++++++++ 7 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt index 54c22cd..0b0ddfc 100644 --- a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt @@ -4,12 +4,23 @@ import com.example.estdelivery.application.port.`in`.DepositUseCase import com.example.estdelivery.application.port.`in`.command.DepositCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.domain.Deposit class DepositService( private val loadAccountPort: LoadAccountPort, private val updateAccountPort: UpdateAccountPort ) : DepositUseCase { - override fun deposit(depositCommand: DepositCommand) { - TODO("Not yet implemented") + /** + * 1. 계좌를 조회한다. + * 2. 계좌에 입금한다. + * 3. 계좌 정보를 업데이트한다. + * + * @param command 입금 명령 + */ + override fun deposit(command: DepositCommand) { + val account = loadAccountPort.findByAccountNumber(command.accountNumber) + val depositCommand = Deposit(account, command.amount, command.depositTime) + depositCommand.deposit() + updateAccountPort.update(account) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt index 9a559a3..d852e80 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt @@ -5,7 +5,7 @@ import com.example.estdelivery.application.port.`in`.command.DepositCommand interface DepositUseCase { /** * 계좌에 돈을 입금한다. - * @param depositCommand + * @param command */ - fun deposit(depositCommand: DepositCommand) + fun deposit(command: DepositCommand) } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt index 0e56fec..56d58ca 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/DepositCommand.kt @@ -1,5 +1,13 @@ package com.example.estdelivery.application.port.`in`.command -class DepositCommand { +import com.example.estdelivery.domain.AccountNumber +import com.example.estdelivery.domain.Money +import jakarta.validation.constraints.PastOrPresent +import java.time.LocalDateTime -} +data class DepositCommand( + val accountNumber: AccountNumber, + val amount: Money, + @field:PastOrPresent + val depositTime: LocalDateTime +) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt index 406af8c..3840599 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/LoadAccountPort.kt @@ -1,7 +1,9 @@ package com.example.estdelivery.application.port.out +import com.example.estdelivery.domain.Account import com.example.estdelivery.domain.AccountNumber interface LoadAccountPort { fun existsByAccountNumber(accountNumber: AccountNumber): Boolean + fun findByAccountNumber(accountNumber: AccountNumber): Account } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt index 7525090..5b4809c 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/UpdateAccountPort.kt @@ -1,4 +1,7 @@ package com.example.estdelivery.application.port.out +import com.example.estdelivery.domain.Account + interface UpdateAccountPort { + fun update(account: Account) } diff --git a/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt b/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt index a3727c0..01f1b02 100644 --- a/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt +++ b/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt @@ -1,6 +1,7 @@ package com.example.estdelivery import com.example.estdelivery.application.port.`in`.command.CreateAccountCommand +import com.example.estdelivery.application.port.`in`.command.DepositCommand import com.example.estdelivery.domain.Account import com.example.estdelivery.domain.AccountNumber import com.example.estdelivery.domain.AccountTransaction @@ -28,3 +29,4 @@ fun transferHistoryArbitraryBuilder() = fixtureMonkey.giveMeBuilder() fun accountTransactionArbitraryBuilder() = fixtureMonkey.giveMeBuilder() fun accountTransactionsArbitraryBuilder() = fixtureMonkey.giveMeBuilder() +fun depositCommandArbitraryBuilder() = fixtureMonkey.giveMeBuilder() diff --git a/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt b/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt new file mode 100644 index 0000000..3e35dbb --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt @@ -0,0 +1,47 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder +import com.example.estdelivery.application.port.`in`.command.DepositCommand +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.depositCommandArbitraryBuilder +import com.navercorp.fixturemonkey.kotlin.set +import io.kotest.core.spec.style.FreeSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +class DepositServiceTest : FreeSpec({ + + lateinit var updateAccountPort: UpdateAccountPort + lateinit var loadAccountPort: LoadAccountPort + lateinit var depositService: DepositService + + beforeTest { + updateAccountPort = mockk() + loadAccountPort = mockk() + depositService = DepositService(loadAccountPort, updateAccountPort) + } + + "계좌에 돈을 입금한다." { + // given + val accountNumber = accountNumberArbitraryBuilder().sample() + val depositCommand = depositCommandArbitraryBuilder() + .set(DepositCommand::accountNumber, accountNumber) + .sample() + val account = accountArbitraryBuilder() + .set("accountNumber", accountNumber) + .sample() + + // when + every { loadAccountPort.findByAccountNumber(depositCommand.accountNumber) } returns account + every { updateAccountPort.update(account) } returns Unit + + depositService.deposit(depositCommand) + + // then + verify(exactly = 1) { updateAccountPort.update(account) } + } + +}) From 1aec614d9e81d32af921b6aaf948e5e271dce2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:48:37 +0900 Subject: [PATCH 24/32] =?UTF-8?q?feature=20:=20WithdrawService=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/WithdrawService.kt | 15 +++++- .../application/port/in/WithdrawUseCase.kt | 4 +- .../port/in/command/WithdrawCommand.kt | 12 ++++- .../application/WithdrawServiceTest.kt | 48 +++++++++++++++++++ 4 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt index e66587e..07b74fe 100644 --- a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt @@ -4,12 +4,23 @@ import com.example.estdelivery.application.port.`in`.WithdrawUseCase import com.example.estdelivery.application.port.`in`.command.WithdrawCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.domain.Withdrawal class WithdrawService( private val loadAccountPort: LoadAccountPort, private val updateAccountPort: UpdateAccountPort ) : WithdrawUseCase { - override fun withdraw(withdrawCommand: WithdrawCommand) { - TODO("Not yet implemented") + /** + * 1. 계좌를 조회한다. + * 2. 계좌에서 출금한다. + * 3. 계좌 정보를 업데이트한다. + * + * @param command 출금 명령 + */ + override fun withdraw(command: WithdrawCommand) { + val account = loadAccountPort.findByAccountNumber(command.accountNumber) + val withdrawalCommand = Withdrawal(account, command.amount, command.withdrawalTime) + withdrawalCommand.withdraw() + updateAccountPort.update(account) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt index 0896134..6f3afed 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt @@ -6,7 +6,7 @@ interface WithdrawUseCase { /** * 돈을 출금한다. 계좌 잔액은 출금 금액보다 많거나 같아야 한다. * - * @param withdrawCommand 출금 명령 + * @param command 출금 명령 */ - fun withdraw(withdrawCommand: WithdrawCommand) + fun withdraw(command: WithdrawCommand) } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt index 98f2ec2..6052d1d 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/WithdrawCommand.kt @@ -1,5 +1,13 @@ package com.example.estdelivery.application.port.`in`.command -class WithdrawCommand { +import com.example.estdelivery.domain.AccountNumber +import com.example.estdelivery.domain.Money +import jakarta.validation.constraints.PastOrPresent +import java.time.LocalDateTime -} +data class WithdrawCommand( + val accountNumber: AccountNumber, + val amount: Money, + @field:PastOrPresent + val withdrawalTime: LocalDateTime +) diff --git a/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt b/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt new file mode 100644 index 0000000..9b2c163 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt @@ -0,0 +1,48 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder +import com.example.estdelivery.application.port.`in`.command.WithdrawCommand +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.moneyArbitraryBuilder +import io.kotest.core.spec.style.FreeSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import java.time.LocalDateTime + +class WithdrawServiceTest : FreeSpec({ + + lateinit var loadAccountPort: LoadAccountPort + lateinit var updateAccountPort: UpdateAccountPort + lateinit var withdrawService: WithdrawService + + beforeTest { + loadAccountPort = mockk() + updateAccountPort = mockk() + withdrawService = WithdrawService(loadAccountPort, updateAccountPort) + } + + "계좌에서 돈을 출금한다." { + // given + val accountNumber = accountNumberArbitraryBuilder().sample() + val money = moneyArbitraryBuilder().sample() + val account = accountArbitraryBuilder() + .set("accountNumber", accountNumber) + .set("transactions", AccountTransactions()) + .sample() + account.deposit(money, LocalDateTime.now().minusDays(1)) + val withdrawCommand = WithdrawCommand(accountNumber, money, LocalDateTime.now()) + + // when + every { loadAccountPort.findByAccountNumber(withdrawCommand.accountNumber) } returns account + every { updateAccountPort.update(account) } returns Unit + + withdrawService.withdraw(withdrawCommand) + + // then + verify(exactly = 1) { updateAccountPort.update(account) } + } +}) From 8cfb75014e0f26bf2ea5716efeddadd2b266cfbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:56:45 +0900 Subject: [PATCH 25/32] =?UTF-8?q?feature=20:=20TransferService=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/TransferService.kt | 16 ++++- .../application/port/in/TransferUseCase.kt | 4 +- .../port/in/command/TransferCommand.kt | 11 +++- .../application/TransferServiceTest.kt | 63 +++++++++++++++++++ 4 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 src/test/kotlin/com/example/estdelivery/application/TransferServiceTest.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt index 38dbeab..f2bba06 100644 --- a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt @@ -4,12 +4,24 @@ import com.example.estdelivery.application.port.`in`.TransferUseCase import com.example.estdelivery.application.port.`in`.command.TransferCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.domain.Transfer class TransferService( private val loadAccountPort: LoadAccountPort, private val updateAccountPort: UpdateAccountPort ) : TransferUseCase { - override fun transfer(transferCommand: TransferCommand) { - TODO("Not yet implemented") + /** + * 1. 두 계좌를 조회한다. + * 2. 계좌를 이체한다. + * 3. 계좌 정보를 업데이트한다. + * + * @param command 이체 명령 + */ + override fun transfer(command: TransferCommand) { + val sourceAccount = loadAccountPort.findByAccountNumber(command.source) + val targetAccount = loadAccountPort.findByAccountNumber(command.target) + Transfer(sourceAccount, targetAccount, command.amount, command.transferTime).transfer() + updateAccountPort.update(sourceAccount) + updateAccountPort.update(targetAccount) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt index 731755b..07f354c 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt @@ -5,7 +5,7 @@ import com.example.estdelivery.application.port.`in`.command.TransferCommand interface TransferUseCase { /** * 계좌 간 돈을 이체한다. 이체할 계좌 잔액은 이체할 금액보다 많아야 한다. - * @param transferCommand + * @param command */ - fun transfer(transferCommand: TransferCommand) + fun transfer(command: TransferCommand) } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt index 02bbaa1..28cd7d2 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/command/TransferCommand.kt @@ -1,5 +1,12 @@ package com.example.estdelivery.application.port.`in`.command -class TransferCommand { +import com.example.estdelivery.domain.AccountNumber +import com.example.estdelivery.domain.Money +import java.time.LocalDateTime -} +data class TransferCommand( + val source: AccountNumber, + val target: AccountNumber, + val amount: Money, + val transferTime: LocalDateTime +) diff --git a/src/test/kotlin/com/example/estdelivery/application/TransferServiceTest.kt b/src/test/kotlin/com/example/estdelivery/application/TransferServiceTest.kt new file mode 100644 index 0000000..bf41970 --- /dev/null +++ b/src/test/kotlin/com/example/estdelivery/application/TransferServiceTest.kt @@ -0,0 +1,63 @@ +package com.example.estdelivery.application + +import com.example.estdelivery.accountArbitraryBuilder +import com.example.estdelivery.accountNumberArbitraryBuilder +import com.example.estdelivery.application.port.`in`.command.TransferCommand +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.domain.Money +import com.example.estdelivery.moneyArbitraryBuilder +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import java.time.LocalDateTime + +class TransferServiceTest : FreeSpec({ + + lateinit var updateAccountPort: UpdateAccountPort + lateinit var loadAccountPort: LoadAccountPort + lateinit var transferService: TransferService + + beforeTest { + updateAccountPort = mockk() + loadAccountPort = mockk() + transferService = TransferService(loadAccountPort, updateAccountPort) + } + + "계좌 간 돈을 이체한다." { + // given + val money = moneyArbitraryBuilder().sample() + val sourceAccountNumber = accountNumberArbitraryBuilder().sample() + val targetAccountNumber = accountNumberArbitraryBuilder().sample() + val sourceAccount = accountArbitraryBuilder() + .set("accountNumber", sourceAccountNumber) + .set("transactions", AccountTransactions()) + .sample() + val targetAccount = accountArbitraryBuilder() + .set("accountNumber", targetAccountNumber) + .set("transactions", AccountTransactions()) + .sample() + + sourceAccount.deposit(money, LocalDateTime.now().minusDays(1)) + val transferCommand = TransferCommand( + sourceAccountNumber, + targetAccountNumber, + money, + LocalDateTime.now() + ) + + // when + every { loadAccountPort.findByAccountNumber(transferCommand.source) } returns sourceAccount + every { loadAccountPort.findByAccountNumber(transferCommand.target) } returns targetAccount + every { updateAccountPort.update(sourceAccount) } returns Unit + every { updateAccountPort.update(targetAccount) } returns Unit + + transferService.transfer(transferCommand) + + // then + sourceAccount.balance() shouldBe Money.ZERO + targetAccount.balance() shouldBe transferCommand.amount + } +}) From ab85479fa6abc5f889cf24b6e3f9675d1db47562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Sun, 18 Feb 2024 23:07:13 +0900 Subject: [PATCH 26/32] =?UTF-8?q?test=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/FixtureMonkeyUtil.kt | 2 ++ .../estdelivery/application/DepositServiceTest.kt | 9 +++++++-- .../estdelivery/application/WithdrawServiceTest.kt | 4 +++- .../com/example/estdelivery/domain/AccountTest.kt | 3 ++- .../estdelivery/domain/AccountTransactionTest.kt | 5 +++-- .../estdelivery/domain/AccountTransactionsTest.kt | 11 +++++++---- .../example/estdelivery/domain/TransferHistoryTest.kt | 5 ++++- 7 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt b/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt index 01f1b02..5bb6466 100644 --- a/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt +++ b/src/test/kotlin/com/example/estdelivery/FixtureMonkeyUtil.kt @@ -14,6 +14,8 @@ import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitra import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin import com.navercorp.fixturemonkey.kotlin.KotlinPlugin import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import net.jqwik.api.Arbitraries +import java.time.LocalDateTime private val fixtureMonkey: FixtureMonkey = FixtureMonkey.builder() .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) diff --git a/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt b/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt index 3e35dbb..cf13e2a 100644 --- a/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt +++ b/src/test/kotlin/com/example/estdelivery/application/DepositServiceTest.kt @@ -6,8 +6,11 @@ import com.example.estdelivery.application.port.`in`.command.DepositCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort import com.example.estdelivery.depositCommandArbitraryBuilder +import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.moneyArbitraryBuilder import com.navercorp.fixturemonkey.kotlin.set import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import io.mockk.verify @@ -26,12 +29,15 @@ class DepositServiceTest : FreeSpec({ "계좌에 돈을 입금한다." { // given + val money = moneyArbitraryBuilder().sample() val accountNumber = accountNumberArbitraryBuilder().sample() val depositCommand = depositCommandArbitraryBuilder() .set(DepositCommand::accountNumber, accountNumber) + .set(DepositCommand::amount, money) .sample() val account = accountArbitraryBuilder() .set("accountNumber", accountNumber) + .set("transactions", AccountTransactions()) .sample() // when @@ -41,7 +47,6 @@ class DepositServiceTest : FreeSpec({ depositService.deposit(depositCommand) // then - verify(exactly = 1) { updateAccountPort.update(account) } + account.balance() shouldBe money } - }) diff --git a/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt b/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt index 9b2c163..3bfb694 100644 --- a/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt +++ b/src/test/kotlin/com/example/estdelivery/application/WithdrawServiceTest.kt @@ -6,8 +6,10 @@ import com.example.estdelivery.application.port.`in`.command.WithdrawCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.domain.Money import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import io.mockk.verify @@ -43,6 +45,6 @@ class WithdrawServiceTest : FreeSpec({ withdrawService.withdraw(withdrawCommand) // then - verify(exactly = 1) { updateAccountPort.update(account) } + account.balance() shouldBe Money.ZERO } }) diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt index c72c684..d0cb955 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTest.kt @@ -4,6 +4,7 @@ import com.example.estdelivery.accountArbitraryBuilder import com.example.estdelivery.accountNumberArbitraryBuilder import com.example.estdelivery.transferHistoryArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.core.spec.style.FreeSpec @@ -30,7 +31,7 @@ class AccountTest : FreeSpec({ val 계좌_과거_이력 = transferHistories(내_계좌) for (i in 0..10) { "$i 번째 계좌를 생성한다." { - shouldNotThrow { + shouldNotThrowAny { accountArbitraryBuilder() .set("number", 내_계좌) .set("transferHistories", 계좌_과거_이력) diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt index 5ee340b..1abb184 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionTest.kt @@ -2,6 +2,7 @@ package com.example.estdelivery.domain import com.example.estdelivery.accountTransactionArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime @@ -9,7 +10,7 @@ class AccountTransactionTest : FreeSpec({ "계좌 거래 내역을 생성한다." - { for (i in 0..300) { "$i 번째 거래 내역을 생성한다." { - shouldNotThrow { + shouldNotThrowAny { accountTransactionArbitraryBuilder() .sample() } @@ -19,7 +20,7 @@ class AccountTransactionTest : FreeSpec({ "계좌 거래 일자가 미래일 수 없다." { val futureDate = LocalDateTime.now().plusDays(1) - shouldNotThrow { + shouldNotThrowAny { accountTransactionArbitraryBuilder() .set("transactionTime", futureDate) .sample() diff --git a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt index 04ddbbc..a95753e 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/AccountTransactionsTest.kt @@ -3,26 +3,29 @@ package com.example.estdelivery.domain import com.example.estdelivery.accountTransactionsArbitraryBuilder import com.example.estdelivery.moneyArbitraryBuilder import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime class AccountTransactionsTest : FreeSpec({ val money = moneyArbitraryBuilder().sample() - val accountTransactions = accountTransactionsArbitraryBuilder().sample() + val accountTransactions = AccountTransactions() "돈 입금 기록을 추가한다." { - shouldNotThrow { + shouldNotThrowAny { accountTransactions.deposit(money, LocalDateTime.now()) } } "돈 출금 기록을 추가한다." { - shouldNotThrow { + shouldNotThrowAny { accountTransactions.withdraw(money, LocalDateTime.now()) } } "잔액을 조회한다." { - println(accountTransactions.balance()) + shouldNotThrowAny { + accountTransactions.balance() + } } }) diff --git a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt index f41ad6e..c31902c 100644 --- a/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt +++ b/src/test/kotlin/com/example/estdelivery/domain/TransferHistoryTest.kt @@ -3,6 +3,7 @@ package com.example.estdelivery.domain import com.example.estdelivery.accountNumberArbitraryBuilder import com.example.estdelivery.moneyArbitraryBuilder import com.example.estdelivery.transferHistoryArbitraryBuilder +import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FreeSpec import java.time.LocalDateTime @@ -11,7 +12,9 @@ class TransferHistoryTest : FreeSpec({ "300번 중" - { for (i in 0..300) { "$i 번째 송금 내역을 생성한다." { - println(transferHistoryArbitraryBuilder().sample()) + shouldNotThrowAny { + transferHistoryArbitraryBuilder().sample() + } } } } From 74f1d215919355772ed3e217e9ac9b2cc1608276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:02:34 +0900 Subject: [PATCH 27/32] =?UTF-8?q?feature=20:=20=EC=98=81=EC=86=8D=ED=99=94?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/CreateAccountService.kt | 2 + .../estdelivery/application/DepositService.kt | 2 + .../application/TransferService.kt | 2 + .../application/WithdrawService.kt | 2 + .../application/port/out/CreateAccountPort.kt | 2 +- .../port/out/persistence/AccountAdapter.kt | 35 +++++++++++ .../GenerateAccountNumberAdapter.kt | 21 +++++++ .../out/persistence/entity/AccountEntity.kt | 32 ++++++++++ .../entity/AccountTransactionEntity.kt | 25 ++++++++ .../entity/TransferHistoryEntity.kt | 25 ++++++++ .../infra/AccountEntityRepository.kt | 10 +++ .../infra/AccountNumberSequence.kt | 19 ++++++ .../out/persistence/mapper/AccountMapper.kt | 61 +++++++++++++++++++ .../com/example/estdelivery/domain/Account.kt | 7 ++- .../estdelivery/domain/AccountTransaction.kt | 6 +- .../estdelivery/domain/AccountTransactions.kt | 4 ++ .../estdelivery/domain/TransferHistory.kt | 5 ++ 17 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/AccountAdapter.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/GenerateAccountNumberAdapter.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountEntityRepository.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountNumberSequence.kt create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt b/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt index 9064294..e1170c8 100644 --- a/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/CreateAccountService.kt @@ -7,7 +7,9 @@ import com.example.estdelivery.application.port.out.GenerateAccountNumberPort import com.example.estdelivery.domain.Account import com.example.estdelivery.domain.AccountTransactions import com.example.estdelivery.domain.TransferHistories +import org.springframework.stereotype.Service +@Service class CreateAccountService( private val createAccountPort: CreateAccountPort, private val generateAccountNumber: GenerateAccountNumberPort, diff --git a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt index 0b0ddfc..fd83c62 100644 --- a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt @@ -5,7 +5,9 @@ import com.example.estdelivery.application.port.`in`.command.DepositCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort import com.example.estdelivery.domain.Deposit +import org.springframework.stereotype.Service +@Service class DepositService( private val loadAccountPort: LoadAccountPort, private val updateAccountPort: UpdateAccountPort diff --git a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt index f2bba06..f444285 100644 --- a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt @@ -5,7 +5,9 @@ import com.example.estdelivery.application.port.`in`.command.TransferCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort import com.example.estdelivery.domain.Transfer +import org.springframework.stereotype.Service +@Service class TransferService( private val loadAccountPort: LoadAccountPort, private val updateAccountPort: UpdateAccountPort diff --git a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt index 07b74fe..bdf6c2b 100644 --- a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt @@ -5,7 +5,9 @@ import com.example.estdelivery.application.port.`in`.command.WithdrawCommand import com.example.estdelivery.application.port.out.LoadAccountPort import com.example.estdelivery.application.port.out.UpdateAccountPort import com.example.estdelivery.domain.Withdrawal +import org.springframework.stereotype.Service +@Service class WithdrawService( private val loadAccountPort: LoadAccountPort, private val updateAccountPort: UpdateAccountPort diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt index 3ae09bb..70c5127 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/CreateAccountPort.kt @@ -3,5 +3,5 @@ package com.example.estdelivery.application.port.out import com.example.estdelivery.domain.Account interface CreateAccountPort { - fun create(newAccount: Account) + fun create(account: Account) } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/AccountAdapter.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/AccountAdapter.kt new file mode 100644 index 0000000..0d4c3c9 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/AccountAdapter.kt @@ -0,0 +1,35 @@ +package com.example.estdelivery.application.port.out.persistence + +import com.example.estdelivery.application.port.out.CreateAccountPort +import com.example.estdelivery.application.port.out.LoadAccountPort +import com.example.estdelivery.application.port.out.UpdateAccountPort +import com.example.estdelivery.application.port.out.persistence.mapper.fromAccountEntity +import com.example.estdelivery.application.port.out.persistence.mapper.toAccountEntity +import com.example.estdelivery.application.port.out.persistence.infra.AccountEntityRepository +import com.example.estdelivery.domain.Account +import com.example.estdelivery.domain.AccountNumber +import jakarta.transaction.Transactional +import org.springframework.stereotype.Component + +@Component +class AccountAdapter( + private val accountEntityRepository: AccountEntityRepository +) : CreateAccountPort, LoadAccountPort, UpdateAccountPort { + @Transactional + override fun create(account: Account) { + accountEntityRepository.save(toAccountEntity(account)) + } + + @Transactional + override fun update(account: Account) { + accountEntityRepository.save(toAccountEntity(account)) + } + + override fun existsByAccountNumber(accountNumber: AccountNumber) = + accountEntityRepository.existsByAccountNumber(accountNumber) + + override fun findByAccountNumber(accountNumber: AccountNumber) = + fromAccountEntity( + accountEntityRepository.findByAccountNumber(accountNumber) ?: throw NoSuchElementException("Account not found") + ) +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/GenerateAccountNumberAdapter.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/GenerateAccountNumberAdapter.kt new file mode 100644 index 0000000..04aa139 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/GenerateAccountNumberAdapter.kt @@ -0,0 +1,21 @@ +package com.example.estdelivery.application.port.out.persistence + +import com.example.estdelivery.application.port.out.GenerateAccountNumberPort +import com.example.estdelivery.application.port.out.persistence.infra.AccountEntityRepository +import com.example.estdelivery.application.port.out.persistence.infra.AccountNumberSequence +import com.example.estdelivery.domain.AccountNumber +import org.springframework.stereotype.Component + +@Component +class GenerateAccountNumberAdapter( + private val accountNumberSequence: AccountNumberSequence, + private val accountEntityRepository: AccountEntityRepository +) : GenerateAccountNumberPort { + override fun generate(): AccountNumber { + var accountNumber: AccountNumber + do { + accountNumber = AccountNumber(accountNumberSequence.next()) + } while (accountEntityRepository.existsByAccountNumber(accountNumber)) + return accountNumber + } +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt new file mode 100644 index 0000000..30a3407 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt @@ -0,0 +1,32 @@ +package com.example.estdelivery.application.port.out.persistence.entity + +import com.example.estdelivery.domain.AccountNumber +import jakarta.persistence.Column +import jakarta.persistence.Embedded +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.OneToMany +import jakarta.persistence.Table +import java.time.LocalDateTime + +@Entity +@Table(name = "account") +class AccountEntity( + @Embedded + val accountNumber: AccountNumber, + @OneToMany + @JoinColumn(name = "account_id") + val transferHistories: List, + @OneToMany + @JoinColumn(name = "account_id") + val transactions: List, + val createdDate: LocalDateTime, + @Id + @Column(name = "account_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? +) { +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt new file mode 100644 index 0000000..48fd176 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt @@ -0,0 +1,25 @@ +package com.example.estdelivery.application.port.out.persistence.entity + +import com.example.estdelivery.domain.Money +import com.example.estdelivery.domain.TransactionType +import jakarta.persistence.Embedded +import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import java.time.LocalDateTime + +@Entity +class AccountTransactionEntity( + @Embedded + val amount: Money, + @Enumerated(EnumType.STRING) + val type: TransactionType, + val transactionDateTime: LocalDateTime, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null, +) { +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt new file mode 100644 index 0000000..f5e4746 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt @@ -0,0 +1,25 @@ +package com.example.estdelivery.application.port.out.persistence.entity + +import com.example.estdelivery.domain.AccountNumber +import com.example.estdelivery.domain.Money +import jakarta.persistence.Embedded +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import java.time.LocalDateTime + +@Entity +class TransferHistoryEntity( + @Embedded + val sourceAccountNumber: AccountNumber, + @Embedded + val targetAccountNumber: AccountNumber, + @Embedded + val money: Money, + val transferDate: LocalDateTime, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null +) { +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountEntityRepository.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountEntityRepository.kt new file mode 100644 index 0000000..c438492 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountEntityRepository.kt @@ -0,0 +1,10 @@ +package com.example.estdelivery.application.port.out.persistence.infra + +import com.example.estdelivery.application.port.out.persistence.entity.AccountEntity +import com.example.estdelivery.domain.AccountNumber +import org.springframework.data.jpa.repository.JpaRepository + +interface AccountEntityRepository: JpaRepository { + fun existsByAccountNumber(accountNumber: AccountNumber): Boolean + fun findByAccountNumber(accountNumber: AccountNumber): AccountEntity? +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountNumberSequence.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountNumberSequence.kt new file mode 100644 index 0000000..b860231 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/infra/AccountNumberSequence.kt @@ -0,0 +1,19 @@ +package com.example.estdelivery.application.port.out.persistence.infra + +import org.springframework.stereotype.Component +import kotlin.random.Random + +@Component +class AccountNumberSequence { + /** + * 숫자 10 자리를 포함한 문자를 반환한다. + */ + fun next(): String { + val random = Random(System.currentTimeMillis()) + val sb = StringBuilder(10) + for (i in 0 until 10) { + sb.append(random.nextInt(10)) + } + return sb.toString() + } +} diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt new file mode 100644 index 0000000..6336c81 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt @@ -0,0 +1,61 @@ +package com.example.estdelivery.application.port.out.persistence.mapper + +import com.example.estdelivery.application.port.out.persistence.entity.AccountEntity +import com.example.estdelivery.application.port.out.persistence.entity.AccountTransactionEntity +import com.example.estdelivery.application.port.out.persistence.entity.TransferHistoryEntity +import com.example.estdelivery.domain.Account +import com.example.estdelivery.domain.AccountTransaction +import com.example.estdelivery.domain.AccountTransactions +import com.example.estdelivery.domain.TransferHistories +import com.example.estdelivery.domain.TransferHistory + +fun toAccountEntity(newAccount: Account): AccountEntity { + return AccountEntity( + accountNumber = newAccount.showNumber(), + transferHistories = newAccount.showHistories().map { toTransferHistoryEntity(it) }, + transactions = newAccount.showTransactions().map { toAccountTransactionEntity(it) }, + createdDate = newAccount.showCreatedDate(), + id = newAccount.id + ) +} + +fun fromAccountEntity(accountEntity: AccountEntity): Account { + return Account( + number = accountEntity.accountNumber, + transferHistories = TransferHistories(accountEntity.transferHistories.map { fromTransferHistoryEntity(it) }), + transactions = AccountTransactions(accountEntity.transactions.map { fromAccountTransactionEntity(it) }), + createdDate = accountEntity.createdDate, + id = accountEntity.id + ) +} + +private fun toAccountTransactionEntity(it: AccountTransaction) = + AccountTransactionEntity( + amount = it.showAmount(), + type = it.showType(), + transactionDateTime = it.showTransactionTime() + ) + +private fun fromAccountTransactionEntity(it: AccountTransactionEntity) = + AccountTransaction( + amount = it.amount, + type = it.type, + transactionDateTime = it.transactionDateTime + ) + +private fun toTransferHistoryEntity(it: TransferHistory) = + TransferHistoryEntity( + money = it.showAmount(), + sourceAccountNumber = it.showSource(), + targetAccountNumber = it.showTarget(), + transferDate = it.showTransferDate() + ) + +private fun fromTransferHistoryEntity(it: TransferHistoryEntity) = + TransferHistory( + money = it.money, + source = it.sourceAccountNumber, + target = it.targetAccountNumber, + transferDate = it.transferDate + ) + diff --git a/src/main/kotlin/com/example/estdelivery/domain/Account.kt b/src/main/kotlin/com/example/estdelivery/domain/Account.kt index ac173cb..cf575b6 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Account.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Account.kt @@ -9,7 +9,7 @@ class Account( private val transactions: AccountTransactions, @field:PastOrPresent private val createdDate: LocalDateTime, - private val id: Long? = null + val id: Long? = null ) { fun balance(): Money { return transactions.balance() @@ -39,4 +39,9 @@ class Account( fun withdraw(amount: Money, transactionTime: LocalDateTime) { transactions.withdraw(amount, transactionTime) } + + fun showTransactions() = transactions.showTransactions() + fun showHistories() = transferHistories.showHistories() + fun showNumber() = number + fun showCreatedDate() = createdDate } diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt index eadef0f..d192017 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransaction.kt @@ -8,4 +8,8 @@ data class AccountTransaction( val type: TransactionType, @field:PastOrPresent val transactionDateTime: LocalDateTime, -) +) { + fun showAmount() = amount + fun showTransactionTime() = transactionDateTime + fun showType() = type +} diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt index de8da81..f4a0707 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt @@ -23,4 +23,8 @@ class AccountTransactions( } } } + + fun showTransactions(): List { + return accountTransactions + } } diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt index ccad89e..84c028a 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistory.kt @@ -10,6 +10,11 @@ data class TransferHistory( @field:PastOrPresent private val transferDate: LocalDateTime ) { + fun showAmount()= money + fun showSource() = source + fun showTarget() = target + fun showTransferDate() = transferDate + init { require(source != target) { "출금 계좌와 입금 계좌는 같을 수 없습니다." } } From 1664295129beef96a484db14c323dbbe952d7fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:12:45 +0900 Subject: [PATCH 28/32] =?UTF-8?q?refactor=20:=20=EA=B3=84=EC=A2=8C=20?= =?UTF-8?q?=ED=98=84=EA=B8=88=20=EB=B3=80=EB=8F=99=20=ED=9B=84=20=EC=9E=94?= =?UTF-8?q?=EC=95=A1=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=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 --- .../com/example/estdelivery/application/DepositService.kt | 4 +++- .../com/example/estdelivery/application/TransferService.kt | 4 +++- .../com/example/estdelivery/application/WithdrawService.kt | 4 +++- .../estdelivery/application/port/in/AccountResponse.kt | 7 +++++++ .../application/port/in/CreateAccountUseCase.kt | 5 +++-- .../estdelivery/application/port/in/DepositUseCase.kt | 2 +- .../estdelivery/application/port/in/TransferUseCase.kt | 2 +- .../estdelivery/application/port/in/WithdrawUseCase.kt | 2 +- 8 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/AccountResponse.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt index fd83c62..1460651 100644 --- a/src/main/kotlin/com/example/estdelivery/application/DepositService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/DepositService.kt @@ -1,5 +1,6 @@ package com.example.estdelivery.application +import com.example.estdelivery.application.port.`in`.AccountResponse import com.example.estdelivery.application.port.`in`.DepositUseCase import com.example.estdelivery.application.port.`in`.command.DepositCommand import com.example.estdelivery.application.port.out.LoadAccountPort @@ -19,10 +20,11 @@ class DepositService( * * @param command 입금 명령 */ - override fun deposit(command: DepositCommand) { + override fun deposit(command: DepositCommand): AccountResponse { val account = loadAccountPort.findByAccountNumber(command.accountNumber) val depositCommand = Deposit(account, command.amount, command.depositTime) depositCommand.deposit() updateAccountPort.update(account) + return AccountResponse(account.balance()) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt index f444285..b016741 100644 --- a/src/main/kotlin/com/example/estdelivery/application/TransferService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/TransferService.kt @@ -1,5 +1,6 @@ package com.example.estdelivery.application +import com.example.estdelivery.application.port.`in`.AccountResponse import com.example.estdelivery.application.port.`in`.TransferUseCase import com.example.estdelivery.application.port.`in`.command.TransferCommand import com.example.estdelivery.application.port.out.LoadAccountPort @@ -19,11 +20,12 @@ class TransferService( * * @param command 이체 명령 */ - override fun transfer(command: TransferCommand) { + override fun transfer(command: TransferCommand): AccountResponse { val sourceAccount = loadAccountPort.findByAccountNumber(command.source) val targetAccount = loadAccountPort.findByAccountNumber(command.target) Transfer(sourceAccount, targetAccount, command.amount, command.transferTime).transfer() updateAccountPort.update(sourceAccount) updateAccountPort.update(targetAccount) + return AccountResponse(sourceAccount.balance()) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt index bdf6c2b..a8bd6f9 100644 --- a/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt +++ b/src/main/kotlin/com/example/estdelivery/application/WithdrawService.kt @@ -1,5 +1,6 @@ package com.example.estdelivery.application +import com.example.estdelivery.application.port.`in`.AccountResponse import com.example.estdelivery.application.port.`in`.WithdrawUseCase import com.example.estdelivery.application.port.`in`.command.WithdrawCommand import com.example.estdelivery.application.port.out.LoadAccountPort @@ -19,10 +20,11 @@ class WithdrawService( * * @param command 출금 명령 */ - override fun withdraw(command: WithdrawCommand) { + override fun withdraw(command: WithdrawCommand): AccountResponse { val account = loadAccountPort.findByAccountNumber(command.accountNumber) val withdrawalCommand = Withdrawal(account, command.amount, command.withdrawalTime) withdrawalCommand.withdraw() updateAccountPort.update(account) + return AccountResponse(account.balance()) } } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/AccountResponse.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/AccountResponse.kt new file mode 100644 index 0000000..396ab09 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/AccountResponse.kt @@ -0,0 +1,7 @@ +package com.example.estdelivery.application.port.`in` + +import com.example.estdelivery.domain.Money + +class AccountResponse( + val balance: Money +) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt index 6d07183..ad86629 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/CreateAccountUseCase.kt @@ -5,7 +5,8 @@ import com.example.estdelivery.application.port.`in`.command.CreateAccountComman interface CreateAccountUseCase { /** * 계좌를 생성한다. 생성되는 계좌는 고유하며 잔액은 0원이다. - * @param createAccountCommand + * + * @param command */ - fun createAccount(createAccountCommand: CreateAccountCommand) + fun createAccount(command: CreateAccountCommand) } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt index d852e80..a592361 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/DepositUseCase.kt @@ -7,5 +7,5 @@ interface DepositUseCase { * 계좌에 돈을 입금한다. * @param command */ - fun deposit(command: DepositCommand) + fun deposit(command: DepositCommand) : AccountResponse } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt index 07f354c..b4c73a0 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/TransferUseCase.kt @@ -7,5 +7,5 @@ interface TransferUseCase { * 계좌 간 돈을 이체한다. 이체할 계좌 잔액은 이체할 금액보다 많아야 한다. * @param command */ - fun transfer(command: TransferCommand) + fun transfer(command: TransferCommand) : AccountResponse } diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt index 6f3afed..16bba87 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/WithdrawUseCase.kt @@ -8,5 +8,5 @@ interface WithdrawUseCase { * * @param command 출금 명령 */ - fun withdraw(command: WithdrawCommand) + fun withdraw(command: WithdrawCommand) : AccountResponse } From dcc470897324f07b96ec8e9d8aa5a068ceea890b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:21:46 +0900 Subject: [PATCH 29/32] =?UTF-8?q?fix=20:=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=20=ED=95=84=EB=93=9C=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=8B=A4=ED=8C=A8=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 --- .../port/out/persistence/entity/TransferHistoryEntity.kt | 7 ++++++- .../port/out/persistence/mapper/AccountMapper.kt | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt index f5e4746..32533f0 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt @@ -2,6 +2,8 @@ package com.example.estdelivery.application.port.out.persistence.entity import com.example.estdelivery.domain.AccountNumber import com.example.estdelivery.domain.Money +import jakarta.persistence.AttributeOverride +import jakarta.persistence.Column import jakarta.persistence.Embedded import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue @@ -12,13 +14,16 @@ import java.time.LocalDateTime @Entity class TransferHistoryEntity( @Embedded + @AttributeOverride(name = "accountNumber", column = Column(name = "source_account_number")) val sourceAccountNumber: AccountNumber, @Embedded + @AttributeOverride(name = "accountNumber", column = Column(name = "target_account_number")) val targetAccountNumber: AccountNumber, @Embedded - val money: Money, + val amount: Money, val transferDate: LocalDateTime, @Id + @Column(name = "transfer_id") @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null ) { diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt index 6336c81..4c16642 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/mapper/AccountMapper.kt @@ -45,7 +45,7 @@ private fun fromAccountTransactionEntity(it: AccountTransactionEntity) = private fun toTransferHistoryEntity(it: TransferHistory) = TransferHistoryEntity( - money = it.showAmount(), + amount = it.showAmount(), sourceAccountNumber = it.showSource(), targetAccountNumber = it.showTarget(), transferDate = it.showTransferDate() @@ -53,7 +53,7 @@ private fun toTransferHistoryEntity(it: TransferHistory) = private fun fromTransferHistoryEntity(it: TransferHistoryEntity) = TransferHistory( - money = it.money, + money = it.amount, source = it.sourceAccountNumber, target = it.targetAccountNumber, transferDate = it.transferDate From 4d535b3a039e60ae48fc32aeffe8796959f6fb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:22:19 +0900 Subject: [PATCH 30/32] =?UTF-8?q?refactor=20:=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EB=B8=94=EB=A1=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/port/out/persistence/entity/AccountEntity.kt | 3 +-- .../port/out/persistence/entity/AccountTransactionEntity.kt | 3 +-- .../port/out/persistence/entity/TransferHistoryEntity.kt | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt index 30a3407..bac432f 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountEntity.kt @@ -28,5 +28,4 @@ class AccountEntity( @Column(name = "account_id") @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long? -) { -} +) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt index 48fd176..c506099 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/AccountTransactionEntity.kt @@ -21,5 +21,4 @@ class AccountTransactionEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, -) { -} +) diff --git a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt index 32533f0..97873c1 100644 --- a/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt +++ b/src/main/kotlin/com/example/estdelivery/application/port/out/persistence/entity/TransferHistoryEntity.kt @@ -26,5 +26,4 @@ class TransferHistoryEntity( @Column(name = "transfer_id") @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null -) { -} +) From 8766e68dcd5b070637be2c1f7812ca11d5343416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:22:29 +0900 Subject: [PATCH 31/32] =?UTF-8?q?feature=20:=20AccountController=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../port/in/web/AccountController.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/kotlin/com/example/estdelivery/application/port/in/web/AccountController.kt diff --git a/src/main/kotlin/com/example/estdelivery/application/port/in/web/AccountController.kt b/src/main/kotlin/com/example/estdelivery/application/port/in/web/AccountController.kt new file mode 100644 index 0000000..4ec6808 --- /dev/null +++ b/src/main/kotlin/com/example/estdelivery/application/port/in/web/AccountController.kt @@ -0,0 +1,36 @@ +package com.example.estdelivery.application.port.`in`.web + +import com.example.estdelivery.application.port.`in`.CreateAccountUseCase +import com.example.estdelivery.application.port.`in`.DepositUseCase +import com.example.estdelivery.application.port.`in`.TransferUseCase +import com.example.estdelivery.application.port.`in`.WithdrawUseCase +import com.example.estdelivery.application.port.`in`.command.CreateAccountCommand +import com.example.estdelivery.application.port.`in`.command.DepositCommand +import com.example.estdelivery.application.port.`in`.command.TransferCommand +import com.example.estdelivery.application.port.`in`.command.WithdrawCommand +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/accounts") +class AccountController( + private val createAccountUseCase: CreateAccountUseCase, + private val depositUseCase: DepositUseCase, + private val withdrawUseCase: WithdrawUseCase, + private val transferUseCase: TransferUseCase +) { + @PostMapping + fun createAccount(createAccountCommand: CreateAccountCommand) { + createAccountUseCase.createAccount(createAccountCommand) + } + + @PostMapping("/deposit") + fun deposit(depositCommand: DepositCommand) = depositUseCase.deposit(depositCommand) + + @PostMapping("/withdraw") + fun withdraw(withdrawCommand: WithdrawCommand) = withdrawUseCase.withdraw(withdrawCommand) + + @PostMapping("/transfer") + fun transfer(transferCommand: TransferCommand) = transferUseCase.transfer(transferCommand) +} From 99e40241aabc1bad32576f64f72e9fec7ea4e4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=80=E1=85=A5=E1=86=AB=E1=84=8E?= =?UTF-8?q?=E1=85=A1=E1=86=BC?= <92219795+this-is-spear@users.noreply.github.com> Date: Mon, 19 Feb 2024 07:49:22 +0900 Subject: [PATCH 32/32] =?UTF-8?q?refactor=20:=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EA=B2=BD=EB=9F=89=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/estdelivery/domain/Account.kt | 13 ++++--------- .../estdelivery/domain/AccountTransactions.kt | 18 +++++++----------- .../com/example/estdelivery/domain/Money.kt | 12 +++--------- .../estdelivery/domain/TransferHistories.kt | 4 +--- 4 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/main/kotlin/com/example/estdelivery/domain/Account.kt b/src/main/kotlin/com/example/estdelivery/domain/Account.kt index cf575b6..eaa6efd 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Account.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Account.kt @@ -11,9 +11,7 @@ class Account( private val createdDate: LocalDateTime, val id: Long? = null ) { - fun balance(): Money { - return transactions.balance() - } + fun balance() = transactions.balance() override fun equals(other: Any?): Boolean { if (this === other) return true @@ -24,13 +22,10 @@ class Account( return id == other.id } - override fun hashCode(): Int { - return id?.hashCode() ?: 0 - } + override fun hashCode() = id?.hashCode() ?: 0 - override fun toString(): String { - return "Account(number=$number, balance=${balance()}, transferHistories=$transferHistories, createdDate=$createdDate, id=$id)" - } + override fun toString() = + "Account(number=$number, balance=${balance()}, transferHistories=$transferHistories, createdDate=$createdDate, id=$id)" fun deposit(amount: Money, transactionTime: LocalDateTime) { transactions.deposit(amount, transactionTime) diff --git a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt index f4a0707..a14fefe 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/AccountTransactions.kt @@ -14,17 +14,13 @@ class AccountTransactions( accountTransactions + AccountTransaction(amount, TransactionType.WITHDRAWAL, transactionTime) } - fun balance(): Money { - return accountTransactions.sortedBy { it.transactionDateTime } - .fold(Money.ZERO) { acc, accountTransaction -> - when (accountTransaction.type) { - TransactionType.DEPOSIT -> acc + accountTransaction.amount - TransactionType.WITHDRAWAL -> acc - accountTransaction.amount - } + fun balance() = accountTransactions.sortedBy { it.transactionDateTime } + .fold(Money.ZERO) { acc, accountTransaction -> + when (accountTransaction.type) { + TransactionType.DEPOSIT -> acc + accountTransaction.amount + TransactionType.WITHDRAWAL -> acc - accountTransaction.amount } - } + } - fun showTransactions(): List { - return accountTransactions - } + fun showTransactions() = accountTransactions } diff --git a/src/main/kotlin/com/example/estdelivery/domain/Money.kt b/src/main/kotlin/com/example/estdelivery/domain/Money.kt index 09ca449..b5490f7 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/Money.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/Money.kt @@ -15,15 +15,9 @@ data class Money( val ZERO: Money = Money(BigInteger.ZERO) } - operator fun plus(amount: Money): Money { - return Money(this.amount.add(amount.amount)) - } + operator fun plus(amount: Money) = Money(this.amount.add(amount.amount)) - operator fun minus(amount: Money): Money { - return Money(this.amount.subtract(amount.amount)) - } + operator fun minus(amount: Money) = Money(this.amount.subtract(amount.amount)) - operator fun compareTo(amount: Money): Int { - return this.amount.compareTo(amount.amount) - } + operator fun compareTo(amount: Money) = this.amount.compareTo(amount.amount) } diff --git a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt index 24d58f9..799f2e0 100644 --- a/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt +++ b/src/main/kotlin/com/example/estdelivery/domain/TransferHistories.kt @@ -15,7 +15,5 @@ class TransferHistories( transferHistories = transferHistories - transferHistory } - override fun toString(): String { - return "TransferHistories(transferHistories=$transferHistories)" - } + override fun toString() = "TransferHistories(transferHistories=$transferHistories)" }