From 3c847937dcfff8e39133cf78e2fe68759f906add Mon Sep 17 00:00:00 2001 From: Sim-km Date: Sun, 8 Jun 2025 22:28:34 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=8F=AC=ED=8A=B8=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B0=9C=EC=8B=A0=EC=9E=90=20=EC=9D=B4=EB=A6=84=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `LetterQueryService`와 `LetterCommandService`에서 `UserManagementPort` 삭제. - `senderName` 기본값 처리 로직 단순화 (`ANONYMOUS_SENDER_NAME` 사용). - 엔터티(`ReceiveLetterEntity`, `SendLetterEntity`)에서 `senderName`을 `sender?.username` 기반으로 계산하도록 수정. - 불필요한 변수와 로직 제거로 코드 최적화. --- .../application/letter/service/LetterCommandService.kt | 7 ++----- .../asap/application/letter/service/LetterQueryService.kt | 7 ++----- .../persistence/jpa/letter/entity/ReceiveLetterEntity.kt | 2 ++ .../asap/persistence/jpa/letter/entity/SendLetterEntity.kt | 1 + 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterCommandService.kt b/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterCommandService.kt index 61a912f..2da1147 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterCommandService.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterCommandService.kt @@ -106,16 +106,13 @@ class LetterCommandService( receiverId = DomainId(command.userId), letterId = DomainId(command.letterId), ) + val independentLetter = IndependentLetter.create( sender = SenderInfo( senderId = sendLetter.senderId, - senderName = - sendLetter.senderName - ?: sendLetter.senderId - ?.let { userManagementPort.getUserNotNull(it).username } - .orEmpty(), + senderName = sendLetter.senderName ?: ANONYMOUS_SENDER_NAME, ), receiver = ReceiverInfo( diff --git a/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt b/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt index 44bf6df..2d29ec6 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt @@ -5,7 +5,6 @@ import com.asap.application.letter.port.out.IndependentLetterManagementPort import com.asap.application.letter.port.out.SendLetterManagementPort import com.asap.application.letter.port.out.SpaceLetterManagementPort import com.asap.application.space.port.out.SpaceManagementPort -import com.asap.application.user.port.out.UserManagementPort import com.asap.common.page.PageRequest import com.asap.common.page.Sort import com.asap.domain.common.DomainId @@ -16,7 +15,6 @@ import org.springframework.transaction.annotation.Transactional @Transactional(readOnly = true) class LetterQueryService( private val sendLetterManagementPort: SendLetterManagementPort, - private val userManagementPort: UserManagementPort, private val independentLetterManagementPort: IndependentLetterManagementPort, private val spaceLetterManagementPort: SpaceLetterManagementPort, private val spaceManagementPort: SpaceManagementPort, @@ -32,9 +30,8 @@ class LetterQueryService( receiverId = DomainId(query.userId), letterId = DomainId(query.letterId), ).also { - val sender = it.senderId?.let { userManagementPort.getUserNotNull(it) } return GetVerifiedLetterUsecase.Response( - senderName = sender?.username, + senderName = it.senderName, content = it.content.content, sendDate = it.createdDate, templateType = it.content.templateType, @@ -76,7 +73,7 @@ class LetterQueryService( independentLetterManagementPort.getNearbyLetter(DomainId(query.userId), DomainId(query.letterId)) return GetIndependentLettersUsecase.Response.One( senderName = letter.sender.senderName, - letterCount = letterCount.toLong(), + letterCount = letterCount, content = letter.content.content, sendDate = letter.receiveDate, images = letter.content.images, diff --git a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/ReceiveLetterEntity.kt b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/ReceiveLetterEntity.kt index 4dafeb1..9b34e03 100644 --- a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/ReceiveLetterEntity.kt +++ b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/ReceiveLetterEntity.kt @@ -53,7 +53,9 @@ class ReceiveLetterEntity( @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "sender_id", insertable = false, updatable = false) var sender: UserEntity? = null + var senderName: String = senderName + get() = sender?.username ?: field @Column( name = "receiver_id", diff --git a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/SendLetterEntity.kt b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/SendLetterEntity.kt index 7a70ee5..9b3d7ab 100644 --- a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/SendLetterEntity.kt +++ b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/entity/SendLetterEntity.kt @@ -55,6 +55,7 @@ class SendLetterEntity( @Column(name = "sender_name") var senderName: String? = senderName + get() = sender?.username ?: field @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( From 22cb0e3b0cb1f58ac4329c8eccc21717ebc9f308 Mon Sep 17 00:00:00 2001 From: Sim-km Date: Sun, 8 Jun 2025 22:29:41 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=EC=9D=B5=EB=AA=85=20=EB=B0=8F=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=20=ED=8E=B8=EC=A7=80=20=EB=B0=9C=EC=8B=A0=EC=9E=90=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 회원 및 비회원 발신자에 대한 이름 처리 로직 추가(`LetterQueryService`). - `UserManagementPort` 의존성 삭제 및 관련 코드 변경. - 발신자가 익명인 경우 "비회원 발신자"로 이름이 표시되도록 수정. - 테스트 케이스 추가 및 기존 테스트 로직 최적화. - `LetterFixture`에 익명 발신자 생성 헬퍼 메서드 추가. --- .../letter/service/LetterQueryServiceTest.kt | 309 ++++++++++++------ .../kotlin/com/asap/domain/LetterFixture.kt | 23 +- 2 files changed, 234 insertions(+), 98 deletions(-) diff --git a/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt b/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt index 6baa76b..390c047 100644 --- a/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt +++ b/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt @@ -5,7 +5,6 @@ import com.asap.application.letter.port.out.IndependentLetterManagementPort import com.asap.application.letter.port.out.SendLetterManagementPort import com.asap.application.letter.port.out.SpaceLetterManagementPort import com.asap.application.space.port.out.SpaceManagementPort -import com.asap.application.user.port.out.UserManagementPort import com.asap.domain.LetterFixture import com.asap.domain.SpaceFixture import com.asap.domain.UserFixture @@ -20,7 +19,6 @@ class LetterQueryServiceTest : BehaviorSpec({ val mockSendLetterManagementPort = mockk(relaxed = true) - val mockUserManagementPort = mockk(relaxed = true) val mockIndependentLetterManagementPort = mockk(relaxed = true) val mockSpaceLetterManagementPort = mockk(relaxed = true) val mockSpaceManagementPort = mockk(relaxed = true) @@ -28,7 +26,6 @@ class LetterQueryServiceTest : val letterQueryService = LetterQueryService( mockSendLetterManagementPort, - mockUserManagementPort, mockIndependentLetterManagementPort, mockSpaceLetterManagementPort, mockSpaceManagementPort, @@ -41,27 +38,48 @@ class LetterQueryServiceTest : letterId = "letter-id", userId = user.id.value, ) - val mockSendLetter = LetterFixture.generateSendLetter(user.id) - val mockSender = UserFixture.createUser(mockSendLetter.senderId!!, "sender-name") - every { - mockSendLetterManagementPort.getReadLetterNotNull( - receiverId = DomainId(query.userId), - letterId = DomainId(query.letterId), - ) - } returns mockSendLetter - every { - mockUserManagementPort.getUserNotNull(mockSender.id) - } returns mockSender - `when`("편지가 존재하면") { + + `when`("회원이 보낸 편지가 존재하면") { + val mockSendLetter = LetterFixture.generateSendLetter(user.id) + every { + mockSendLetterManagementPort.getReadLetterNotNull( + receiverId = DomainId(query.userId), + letterId = DomainId(query.letterId), + ) + } returns mockSendLetter + val response = letterQueryService.get(query) - then("편지 정보를 가져와야 한다") { - response.senderName shouldBe mockSender.username + then("발신자 이름은 mapper에서 처리된 이름이어야 한다") { + response.senderName shouldBe mockSendLetter.senderName response.content shouldBe mockSendLetter.content.content response.sendDate shouldBe mockSendLetter.createdDate response.templateType shouldBe mockSendLetter.content.templateType response.images shouldBe mockSendLetter.content.images } } + + `when`("익명으로 보낸 편지가 존재하면") { + val anonymousSenderName = "익명 발신자" + val mockAnonymousLetter = LetterFixture.generateAnonymousSendLetter( + receiverId = user.id, + senderName = anonymousSenderName + ) + every { + mockSendLetterManagementPort.getReadLetterNotNull( + receiverId = DomainId(query.userId), + letterId = DomainId(query.letterId), + ) + } returns mockAnonymousLetter + + val response = letterQueryService.get(query) + then("발신자 이름은 저장된 senderName이어야 한다") { + response.senderName shouldBe anonymousSenderName + response.content shouldBe mockAnonymousLetter.content.content + response.sendDate shouldBe mockAnonymousLetter.createdDate + response.templateType shouldBe mockAnonymousLetter.content.templateType + response.images shouldBe mockAnonymousLetter.content.images + } + } } given("모든 무소속 편지를 조회할 떄") { @@ -69,23 +87,29 @@ class LetterQueryServiceTest : GetIndependentLettersUsecase.QueryAll( userId = "user-id", ) - val mockLetters = - listOf( - LetterFixture.generateIndependentLetter( - senderId = DomainId.generate(), - senderName = "sender-name", - receiverId = DomainId(queryAll.userId), - ), + + `when`("회원과 비회원 편지가 함께 존재하면") { + val memberLetter = LetterFixture.generateIndependentLetter( + senderId = DomainId.generate(), + senderName = "회원 발신자", + receiverId = DomainId(queryAll.userId), + ) + val anonymousLetter = LetterFixture.generateIndependentLetter( + senderId = null, + senderName = "비회원 발신자", + receiverId = DomainId(queryAll.userId), ) - every { - mockIndependentLetterManagementPort.getAllByReceiverId(DomainId(queryAll.userId)) - } returns mockLetters - `when`("편지가 존재하면") { + val mockLetters = listOf(memberLetter, anonymousLetter) + + every { + mockIndependentLetterManagementPort.getAllByReceiverId(DomainId(queryAll.userId)) + } returns mockLetters + val response = letterQueryService.getAll(queryAll) - then("편지 정보를 가져와야 한다") { - response.letters[0].letterId shouldBe mockLetters[0].id.value - response.letters[0].senderName shouldBe mockLetters[0].sender.senderName - response.letters[0].isNew shouldBe mockLetters[0].isNew() + then("모든 편지의 발신자 이름이 정상적으로 표시되어야 한다") { + response.letters.size shouldBe 2 + val senderNames = response.letters.map { it.senderName }.toSet() + senderNames shouldBe setOf("회원 발신자", "비회원 발신자") } } } @@ -100,40 +124,46 @@ class LetterQueryServiceTest : SpaceFixture.createSpace( userId = DomainId(query.userId), ) - val spaceLetter = LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id) - val prevSpaceLetter = - LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id) - val nextSpaceLetter = - LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id) - every { - mockSpaceLetterManagementPort.getSpaceLetterNotNull( - DomainId(query.letterId), - DomainId(query.userId), - ) - } returns spaceLetter - every { - mockSpaceManagementPort.getSpaceNotNull( - spaceLetter.receiver.receiverId, - spaceLetter.spaceId, - ) - } returns space - every { - mockSpaceLetterManagementPort.countSpaceLetterBy( - spaceLetter.spaceId, - spaceLetter.receiver.receiverId, + + `when`("회원이 보낸 행성 편지가 존재하면") { + val spaceLetter = LetterFixture.generateSpaceLetter( + receiverId = DomainId(query.userId), + spaceId = space.id, + senderName = "회원 발신자" ) - } returns 3 - every { - mockSpaceLetterManagementPort.getNearbyLetter( - spaceId = spaceLetter.spaceId, - userId = spaceLetter.receiver.receiverId, - letterId = spaceLetter.id, - ) - } returns Pair(prevSpaceLetter, nextSpaceLetter) - `when`("편지가 존재하면") { + val prevSpaceLetter = + LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id) + val nextSpaceLetter = + LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id) + every { + mockSpaceLetterManagementPort.getSpaceLetterNotNull( + DomainId(query.letterId), + DomainId(query.userId), + ) + } returns spaceLetter + every { + mockSpaceManagementPort.getSpaceNotNull( + spaceLetter.receiver.receiverId, + spaceLetter.spaceId, + ) + } returns space + every { + mockSpaceLetterManagementPort.countSpaceLetterBy( + spaceLetter.spaceId, + spaceLetter.receiver.receiverId, + ) + } returns 3 + every { + mockSpaceLetterManagementPort.getNearbyLetter( + spaceId = spaceLetter.spaceId, + userId = spaceLetter.receiver.receiverId, + letterId = spaceLetter.id, + ) + } returns Pair(prevSpaceLetter, nextSpaceLetter) + val response = letterQueryService.get(query) then("편지 정보를 가져와야 한다") { - response.senderName shouldBe spaceLetter.sender.senderName + response.senderName shouldBe "회원 발신자" response.spaceName shouldBe space.name response.letterCount shouldBe 3 response.content shouldBe spaceLetter.content.content @@ -150,6 +180,53 @@ class LetterQueryServiceTest : } } } + + `when`("비회원이 보낸 행성 편지가 존재하면") { + val anonymousSpaceLetter = LetterFixture.generateSpaceLetter( + receiverId = DomainId(query.userId), + spaceId = space.id, + senderId = null, + senderName = "비회원 발신자" + ) + every { + mockSpaceLetterManagementPort.getSpaceLetterNotNull( + DomainId(query.letterId), + DomainId(query.userId), + ) + } returns anonymousSpaceLetter + every { + mockSpaceManagementPort.getSpaceNotNull( + anonymousSpaceLetter.receiver.receiverId, + anonymousSpaceLetter.spaceId, + ) + } returns space + every { + mockSpaceLetterManagementPort.countSpaceLetterBy( + anonymousSpaceLetter.spaceId, + anonymousSpaceLetter.receiver.receiverId, + ) + } returns 1 + every { + mockSpaceLetterManagementPort.getNearbyLetter( + spaceId = anonymousSpaceLetter.spaceId, + userId = anonymousSpaceLetter.receiver.receiverId, + letterId = anonymousSpaceLetter.id, + ) + } returns Pair(null, null) + + val response = letterQueryService.get(query) + then("비회원 발신자 이름이 정상적으로 표시되어야 한다") { + response.senderName shouldBe "비회원 발신자" + response.spaceName shouldBe space.name + response.letterCount shouldBe 1 + response.content shouldBe anonymousSpaceLetter.content.content + response.receiveDate shouldBe anonymousSpaceLetter.receiveDate + response.images shouldBe anonymousSpaceLetter.content.images + response.templateType shouldBe anonymousSpaceLetter.content.templateType + response.prevLetter shouldBe null + response.nextLetter shouldBe null + } + } } given("궤도 편지 상세 정보를 조회할 때") { @@ -158,41 +235,43 @@ class LetterQueryServiceTest : userId = "user-id", letterId = "letter-id", ) - val independentLetter = - LetterFixture.generateIndependentLetter( - senderId = DomainId.generate(), - senderName = "sender-name", - receiverId = DomainId(query.userId), - ) - val prevIndependentLetter = - LetterFixture.generateIndependentLetter( - senderId = DomainId.generate(), - senderName = "prev-sender-name", - receiverId = DomainId(query.userId), - ) + + `when`("회원이 보낸 독립 편지가 존재하면") { + val independentLetter = + LetterFixture.generateIndependentLetter( + senderId = DomainId.generate(), + senderName = "sender-name", + receiverId = DomainId(query.userId), + ) + val prevIndependentLetter = + LetterFixture.generateIndependentLetter( + senderId = DomainId.generate(), + senderName = "prev-sender-name", + receiverId = DomainId(query.userId), + ) - val nextIndependentLetter = - LetterFixture.generateIndependentLetter( - senderId = DomainId.generate(), - senderName = "next-sender-name", - receiverId = DomainId(query.userId), - ) - every { - mockIndependentLetterManagementPort.getIndependentLetterByIdNotNull( - DomainId(query.letterId), - DomainId(query.userId), - ) - } returns independentLetter - every { - mockIndependentLetterManagementPort.getNearbyLetter( - userId = DomainId(query.userId), - letterId = DomainId(query.letterId), - ) - } returns Pair(prevIndependentLetter, nextIndependentLetter) - every { - mockIndependentLetterManagementPort.countIndependentLetterByReceiverId(DomainId(query.userId)) - } returns 3 - `when`("편지가 존재하면") { + val nextIndependentLetter = + LetterFixture.generateIndependentLetter( + senderId = DomainId.generate(), + senderName = "next-sender-name", + receiverId = DomainId(query.userId), + ) + every { + mockIndependentLetterManagementPort.getIndependentLetterByIdNotNull( + DomainId(query.letterId), + DomainId(query.userId), + ) + } returns independentLetter + every { + mockIndependentLetterManagementPort.getNearbyLetter( + userId = DomainId(query.userId), + letterId = DomainId(query.letterId), + ) + } returns Pair(prevIndependentLetter, nextIndependentLetter) + every { + mockIndependentLetterManagementPort.countIndependentLetterByReceiverId(DomainId(query.userId)) + } returns 3 + val response = letterQueryService.get(query) then("편지 정보를 가져와야 한다") { response.senderName shouldBe independentLetter.sender.senderName @@ -211,6 +290,42 @@ class LetterQueryServiceTest : } } } + + `when`("비회원이 보낸 독립 편지가 존재하면") { + val anonymousIndependentLetter = + LetterFixture.generateIndependentLetter( + senderId = null, + senderName = "비회원 발신자", + receiverId = DomainId(query.userId), + ) + every { + mockIndependentLetterManagementPort.getIndependentLetterByIdNotNull( + DomainId(query.letterId), + DomainId(query.userId), + ) + } returns anonymousIndependentLetter + every { + mockIndependentLetterManagementPort.getNearbyLetter( + userId = DomainId(query.userId), + letterId = DomainId(query.letterId), + ) + } returns Pair(null, null) + every { + mockIndependentLetterManagementPort.countIndependentLetterByReceiverId(DomainId(query.userId)) + } returns 1 + + val response = letterQueryService.get(query) + then("비회원 발신자 이름이 정상적으로 표시되어야 한다") { + response.senderName shouldBe "비회원 발신자" + response.letterCount shouldBe 1 + response.content shouldBe anonymousIndependentLetter.content.content + response.sendDate shouldBe anonymousIndependentLetter.receiveDate + response.images shouldBe anonymousIndependentLetter.content.images + response.templateType shouldBe anonymousIndependentLetter.content.templateType + response.prevLetter shouldBe null + response.nextLetter shouldBe null + } + } } given("전체 편지 조회 요청이 들어올 떄") { diff --git a/Domain-Module/src/testFixtures/kotlin/com/asap/domain/LetterFixture.kt b/Domain-Module/src/testFixtures/kotlin/com/asap/domain/LetterFixture.kt index ce9f1e8..ed409fe 100644 --- a/Domain-Module/src/testFixtures/kotlin/com/asap/domain/LetterFixture.kt +++ b/Domain-Module/src/testFixtures/kotlin/com/asap/domain/LetterFixture.kt @@ -32,11 +32,32 @@ object LetterFixture { status = status, receiverId = receiverId, ) + + fun generateAnonymousSendLetter( + senderName: String = "Anonymous", + receiverName: String = "receiverName", + letterCode: String = "letterCode", + status: LetterStatus = LetterStatus.READ, + receiverId: DomainId = DomainId.generate(), + ): SendLetter = + SendLetter.createAnonymous( + content = + LetterContent( + content = "content", + templateType = 1, + images = mutableListOf("image1", "image2"), + ), + receiverName = receiverName, + letterCode = letterCode, + senderName = senderName, + status = status, + receiverId = receiverId, + ) fun generateIndependentLetter( id: DomainId = DomainId.generate(), content: String = "content", - senderId: DomainId = DomainId.generate(), + senderId: DomainId? = DomainId.generate(), senderName: String = "senderName", receiverId: DomainId = DomainId.generate(), receiveDate: LocalDate = LocalDate.now(),