Skip to content

Commit 9251560

Browse files
authored
테스트 조회 중 풀었던 테스트 여부 필드 추가한다. (#88)
* feat: Add exam response isSolved * refactor: kotlin-jdsl * refactor: ExamWithIsSolved -> ExamResult
1 parent 54b0fd9 commit 9251560

File tree

12 files changed

+210
-44
lines changed

12 files changed

+210
-44
lines changed

api/src/main/kotlin/com/gotchai/api/presentation/v1/exam/ExamController.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ class ExamController(
1818
fun getExams(
1919
@AuthenticationPrincipal
2020
userId: Long
21-
): ExamListResponse = ExamListResponse.from(examQueryUseCase.getExams())
21+
): ExamListResponse = ExamListResponse.from(examQueryUseCase.getExams(userId))
2222

2323
@GetMapping("/exams/{examId}")
2424
fun getExamById(
2525
@AuthenticationPrincipal
2626
userId: Long,
2727
@PathVariable
2828
examId: Long
29-
): ExamResponse = ExamResponse.from(examQueryUseCase.getExamById(examId))
29+
): ExamResponse = ExamResponse.from(examQueryUseCase.getExamById(userId, examId))
3030

3131
@GetMapping("/users/me/exams/solved")
3232
fun getMyExams(
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.gotchai.api.presentation.v1.exam.response
22

3-
import com.gotchai.domain.exam.entity.Exam
3+
import com.gotchai.domain.exam.dto.result.ExamResult
44

55
data class ExamListResponse(
66
val list: List<ExamResponse>
77
) {
88
companion object {
9-
fun from(exams: List<Exam>): ExamListResponse = ExamListResponse(exams.map { ExamResponse.from(it) })
9+
fun from(exams: List<ExamResult>): ExamListResponse = ExamListResponse(exams.map { ExamResponse.from(it) })
1010
}
1111
}

api/src/main/kotlin/com/gotchai/api/presentation/v1/exam/response/ExamResponse.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.gotchai.api.presentation.v1.exam.response
22

3-
import com.gotchai.domain.exam.entity.Exam
3+
import com.gotchai.domain.exam.dto.result.ExamResult
44
import java.time.LocalDateTime
55

66
data class ExamResponse(
@@ -13,11 +13,12 @@ data class ExamResponse(
1313
val iconImage: String,
1414
val coverImage: String,
1515
val theme: String,
16+
val isSolved: Boolean,
1617
val createdAt: LocalDateTime
1718
) {
1819
companion object {
19-
fun from(exam: Exam): ExamResponse =
20-
with(exam) {
20+
fun from(result: ExamResult): ExamResponse =
21+
with(result) {
2122
ExamResponse(
2223
id = id,
2324
title = title,
@@ -28,6 +29,7 @@ data class ExamResponse(
2829
iconImage = iconImage,
2930
coverImage = coverImage,
3031
theme = theme,
32+
isSolved = isSolved,
3133
createdAt = createdAt
3234
)
3335
}

api/src/test/kotlin/com/gotchai/api/presentation/v1/exam/ExamControllerTest.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import com.gotchai.domain.exam.exception.ExamNotFoundException
1515
import com.gotchai.domain.exam.port.`in`.ExamCommandUseCase
1616
import com.gotchai.domain.exam.port.`in`.ExamQueryUseCase
1717
import com.gotchai.domain.fixture.ID
18-
import com.gotchai.domain.fixture.createExam
18+
import com.gotchai.domain.fixture.createExamResult
1919
import com.gotchai.domain.fixture.createStartExamResult
2020
import com.gotchai.domain.fixture.createSubmitExamResult
2121
import com.ninjasquad.springmockk.MockkBean
@@ -32,8 +32,8 @@ class ExamControllerTest : ControllerTest() {
3232
private lateinit var examCommandUseCase: ExamCommandUseCase
3333

3434
init {
35-
describe("getExams()는") {
36-
every { examQueryUseCase.getExams() } returns listOf(createExam())
35+
describe("getExams(userId)는") {
36+
every { examQueryUseCase.getExams(ID) } returns listOf(createExamResult())
3737

3838
it("상태 코드 200과 ExamListResponse를 반환한다.") {
3939
webClient
@@ -49,8 +49,8 @@ class ExamControllerTest : ControllerTest() {
4949
}
5050
}
5151

52-
describe("getMyExams()는") {
53-
every { examQueryUseCase.getExamsByUserId(ID) } returns listOf(createExam())
52+
describe("getMyExams(userId)는") {
53+
every { examQueryUseCase.getExamsByUserId(ID) } returns listOf(createExamResult())
5454

5555
it("상태 코드 200과 ExamListResponse를 반환한다.") {
5656
webClient
@@ -66,9 +66,9 @@ class ExamControllerTest : ControllerTest() {
6666
}
6767
}
6868

69-
describe("getExamById()는") {
69+
describe("getExamById(examId, userId)는") {
7070
context("조회하려는 테스트가 존재하는 경우") {
71-
every { examQueryUseCase.getExamById(ID) } returns createExam()
71+
every { examQueryUseCase.getExamById(ID, ID) } returns createExamResult()
7272

7373
it("상태 코드 200과 ExamResponse를 반환한다.") {
7474
webClient
@@ -86,7 +86,7 @@ class ExamControllerTest : ControllerTest() {
8686
}
8787

8888
context("조회하려는 테스트가 존재하지 않는 경우") {
89-
every { examQueryUseCase.getExamById(any()) } throws ExamNotFoundException()
89+
every { examQueryUseCase.getExamById(any(), any()) } throws ExamNotFoundException()
9090

9191
it("상태 코드 404와 ErrorResponse를 반환한다.") {
9292
webClient
@@ -104,7 +104,7 @@ class ExamControllerTest : ControllerTest() {
104104
}
105105
}
106106

107-
describe("getExamParticipantCount()는") {
107+
describe("getExamParticipantCount(examId)는") {
108108
every { examQueryUseCase.getExamParticipantCountById(ID) } returns PARTICIPANT_COUNT
109109

110110
it("상태 코드 200과 GetExamParticipantCountResponse를 반환한다.") {

api/src/testFixtures/kotlin/com/gotchai/api/docs/ExamDocs.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ val examResponseFields =
2020
ExamResponse::iconImage bodyDesc "아이콘 이미지 URI",
2121
ExamResponse::coverImage bodyDesc "테스트 커버 이미지 URI",
2222
ExamResponse::theme bodyDesc "테마",
23+
ExamResponse::isSolved bodyDesc "테스트 풀이 여부",
2324
ExamResponse::createdAt bodyDesc "생성 날짜"
2425
)
2526

domain/src/main/kotlin/com/gotchai/domain/exam/adapter/in/ExamQueryService.kt

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,39 @@
11
package com.gotchai.domain.exam.adapter.`in`
22

3-
import com.gotchai.domain.exam.entity.Exam
3+
import com.gotchai.domain.exam.dto.result.ExamResult
44
import com.gotchai.domain.exam.exception.ExamNotFoundException
55
import com.gotchai.domain.exam.port.`in`.ExamQueryUseCase
66
import com.gotchai.domain.exam.port.out.ExamHistoryQueryPort
77
import com.gotchai.domain.exam.port.out.ExamQueryPort
8-
import com.gotchai.domain.quiz.port.out.QuizQueryPort
98
import org.springframework.stereotype.Service
109
import org.springframework.transaction.annotation.Transactional
1110

1211
@Service
1312
class ExamQueryService(
1413
private val examQueryPort: ExamQueryPort,
15-
private val examHistoryQueryPort: ExamHistoryQueryPort,
16-
private val quizQueryPort: QuizQueryPort
14+
private val examHistoryQueryPort: ExamHistoryQueryPort
1715
) : ExamQueryUseCase {
1816
@Transactional(readOnly = true)
19-
override fun getExamById(examId: Long): Exam = examQueryPort.getExamById(examId) ?: throw ExamNotFoundException()
17+
override fun getExamById(
18+
userId: Long,
19+
examId: Long
20+
): ExamResult =
21+
ExamResult.from(
22+
examQueryPort.getExamResultsByUserIdAndExamId(userId, examId)
23+
?: throw ExamNotFoundException()
24+
)
2025

2126
@Transactional(readOnly = true)
22-
override fun getExams(): List<Exam> = examQueryPort.getExams()
27+
override fun getExams(userId: Long): List<ExamResult> =
28+
examQueryPort
29+
.getExamResultsByUserId(userId)
30+
.map { ExamResult.from(it) }
2331

2432
@Transactional(readOnly = true)
25-
override fun getExamsByUserId(userId: Long): List<Exam> {
26-
val examHistories = examHistoryQueryPort.getExamHistoriesByUserIdAndSolvedTrue(userId)
27-
val exams = examQueryPort.getExamsByInIn(examHistories.map { it.id })
28-
29-
return exams
30-
}
33+
override fun getExamsByUserId(userId: Long): List<ExamResult> =
34+
examQueryPort
35+
.getExamResultsByUserIdWithSolvedStatus(userId, true)
36+
.map { ExamResult.from(it) }
3137

3238
@Transactional(readOnly = true)
3339
override fun getExamParticipantCountById(examId: Long): Int =
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.gotchai.domain.exam.dto.result
2+
3+
import com.gotchai.domain.exam.entity.ExamWithIsSolved
4+
import java.time.LocalDateTime
5+
6+
data class ExamResult(
7+
val id: Long,
8+
val title: String,
9+
val subTitle: String,
10+
val description: String,
11+
val prompt: String,
12+
val backgroundImage: String,
13+
val iconImage: String,
14+
val coverImage: String,
15+
val theme: String,
16+
val isSolved: Boolean,
17+
val createdAt: LocalDateTime
18+
) {
19+
companion object {
20+
fun from(examWithIsSolved: ExamWithIsSolved): ExamResult =
21+
with(examWithIsSolved) {
22+
ExamResult(
23+
id = id,
24+
title = title,
25+
subTitle = subTitle,
26+
description = description,
27+
prompt = prompt,
28+
backgroundImage = backgroundImage,
29+
iconImage = iconImage,
30+
coverImage = coverImage,
31+
theme = theme,
32+
isSolved = isSolved,
33+
createdAt = createdAt
34+
)
35+
}
36+
}
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.gotchai.domain.exam.entity
2+
3+
import java.time.LocalDateTime
4+
5+
data class ExamWithIsSolved(
6+
val id: Long,
7+
val title: String,
8+
val subTitle: String,
9+
val description: String,
10+
val prompt: String,
11+
val backgroundImage: String,
12+
val iconImage: String,
13+
val coverImage: String,
14+
val theme: String,
15+
val isSolved: Boolean,
16+
val createdAt: LocalDateTime
17+
)
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.gotchai.domain.exam.port.`in`
22

3-
import com.gotchai.domain.exam.entity.Exam
3+
import com.gotchai.domain.exam.dto.result.ExamResult
44

55
interface ExamQueryUseCase {
6-
fun getExamById(examId: Long): Exam
6+
fun getExamById(
7+
userId: Long,
8+
examId: Long
9+
): ExamResult
710

8-
fun getExams(): List<Exam>
11+
fun getExams(userId: Long): List<ExamResult>
912

10-
fun getExamsByUserId(userId: Long): List<Exam>
13+
fun getExamsByUserId(userId: Long): List<ExamResult>
1114

1215
fun getExamParticipantCountById(examId: Long): Int
1316
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
package com.gotchai.domain.exam.port.out
22

33
import com.gotchai.domain.exam.entity.Exam
4+
import com.gotchai.domain.exam.entity.ExamWithIsSolved
45

56
interface ExamQueryPort {
67
fun getExamById(id: Long): Exam?
78

89
fun getExams(): List<Exam>
910

11+
fun getExamResultsByUserIdAndExamId(
12+
userId: Long,
13+
examId: Long
14+
): ExamWithIsSolved?
15+
16+
fun getExamResultsByUserId(userId: Long): List<ExamWithIsSolved>
17+
1018
fun getExamsByInIn(ids: Collection<Long>): List<Exam>
19+
20+
fun getExamResultsByUserIdWithSolvedStatus(
21+
userId: Long,
22+
isSolved: Boolean
23+
): List<ExamWithIsSolved>
1124
}

0 commit comments

Comments
 (0)