Skip to content

Commit 630c7b7

Browse files
authored
내가 푼 테스트 조회에 정답률을 추가한다. (#102)
1 parent 4a018fb commit 630c7b7

File tree

28 files changed

+329
-221
lines changed

28 files changed

+329
-221
lines changed

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

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

2323
@GetMapping("/exams/{examId}")
2424
fun getExamById(
25-
@AuthenticationPrincipal
26-
userId: Long,
2725
@PathVariable
2826
examId: Long
29-
): ExamResponse = ExamResponse.from(examQueryUseCase.getExamById(userId, examId))
27+
): ExamResponse = ExamResponse.from(examQueryUseCase.getExamById(examId))
3028

3129
@GetMapping("/users/me/exams/solved")
3230
fun getMyExams(
3331
@AuthenticationPrincipal
3432
userId: Long
35-
): ExamListResponse =
33+
): GetMyExamListResponse =
3634
examQueryUseCase
37-
.getExamsByUserId(userId)
38-
.let { ExamListResponse.from(it) }
35+
.getMyExams(userId)
36+
.let { GetMyExamListResponse.from(it) }
3937

4038
@GetMapping("/exams/{examId}/participants")
4139
fun getExamParticipantCountById(
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.dto.result.ExamResult
3+
import com.gotchai.domain.exam.entity.Exam
44

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

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

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

3-
import com.gotchai.domain.exam.dto.result.ExamResult
43
import com.gotchai.domain.exam.entity.Exam
54
import java.time.LocalDateTime
65

@@ -14,7 +13,6 @@ data class ExamResponse(
1413
val iconImage: String,
1514
val coverImage: String,
1615
val theme: String,
17-
val isSolved: Boolean,
1816
val createdAt: LocalDateTime
1917
) {
2018
companion object {
@@ -30,24 +28,6 @@ data class ExamResponse(
3028
iconImage = iconImage,
3129
coverImage = coverImage,
3230
theme = theme,
33-
isSolved = false,
34-
createdAt = createdAt
35-
)
36-
}
37-
38-
fun from(result: ExamResult): ExamResponse =
39-
with(result) {
40-
ExamResponse(
41-
id = id,
42-
title = title,
43-
subTitle = subTitle,
44-
description = description,
45-
prompt = prompt,
46-
backgroundImage = backgroundImage,
47-
iconImage = iconImage,
48-
coverImage = coverImage,
49-
theme = theme,
50-
isSolved = isSolved,
5131
createdAt = createdAt
5232
)
5333
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.gotchai.api.presentation.v1.exam.response
2+
3+
import com.gotchai.domain.exam.dto.result.GetExamResult
4+
5+
data class GetExamListResponse(
6+
val list: List<GetExamResponse>
7+
) {
8+
companion object {
9+
fun from(results: List<GetExamResult>): GetExamListResponse = GetExamListResponse(list = results.map { GetExamResponse.from(it) })
10+
}
11+
}

domain/src/main/kotlin/com/gotchai/domain/exam/dto/result/ExamResult.kt renamed to api/src/main/kotlin/com/gotchai/api/presentation/v1/exam/response/GetExamResponse.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package com.gotchai.domain.exam.dto.result
1+
package com.gotchai.api.presentation.v1.exam.response
22

3-
import com.gotchai.domain.exam.dto.projection.ExamWithIsSolved
3+
import com.gotchai.domain.exam.dto.result.GetExamResult
44
import java.time.LocalDateTime
55

6-
data class ExamResult(
6+
data class GetExamResponse(
77
val id: Long,
88
val title: String,
99
val subTitle: String,
@@ -17,9 +17,9 @@ data class ExamResult(
1717
val createdAt: LocalDateTime
1818
) {
1919
companion object {
20-
fun from(examWithIsSolved: ExamWithIsSolved): ExamResult =
21-
with(examWithIsSolved) {
22-
ExamResult(
20+
fun from(result: GetExamResult): GetExamResponse =
21+
with(result) {
22+
GetExamResponse(
2323
id = id,
2424
title = title,
2525
subTitle = subTitle,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.gotchai.api.presentation.v1.exam.response
2+
3+
import com.gotchai.domain.exam.dto.result.GetMyExamResult
4+
5+
data class GetMyExamListResponse(
6+
val list: List<GetMyExamResponse>
7+
) {
8+
companion object {
9+
fun from(results: List<GetMyExamResult>): GetMyExamListResponse = GetMyExamListResponse(results.map { GetMyExamResponse.from(it) })
10+
}
11+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.gotchai.api.presentation.v1.exam.response
2+
3+
import com.gotchai.domain.exam.dto.result.GetMyExamResult
4+
import java.time.LocalDateTime
5+
6+
data class GetMyExamResponse(
7+
val id: Long,
8+
val title: String,
9+
val iconImage: String,
10+
val correctAnswerRate: Int,
11+
val totalQuizCount: Int,
12+
val correctAnswerCount: Int,
13+
val solvedAt: LocalDateTime
14+
) {
15+
companion object {
16+
fun from(result: GetMyExamResult): GetMyExamResponse =
17+
with(result) {
18+
GetMyExamResponse(
19+
id = id,
20+
title = title,
21+
iconImage = iconImage,
22+
correctAnswerRate = correctAnswerRate,
23+
totalQuizCount = totalQuizCount,
24+
correctAnswerCount = correctAnswerCount,
25+
solvedAt = solvedAt
26+
)
27+
}
28+
}
29+
}

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

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,43 +28,43 @@ class ExamControllerTest : ControllerTest() {
2828
private lateinit var examCommandUseCase: ExamCommandUseCase
2929

3030
init {
31-
describe("getExams(userId)는") {
32-
every { examQueryUseCase.getExams(ID) } returns listOf(createExamResult())
31+
describe("getExams()는") {
32+
every { examQueryUseCase.getExams(ID) } returns listOf(createGetExamResult())
3333

34-
it("상태 코드 200과 ExamListResponse를 반환한다.") {
34+
it("상태 코드 200과 GetExamsListResponse를 반환한다.") {
3535
webClient
3636
.get()
3737
.uri("/api/v1/exams")
3838
.exchange()
3939
.expectStatus()
4040
.isOk
41-
.expectBody<ApiResponse<ExamListResponse>>()
41+
.expectBody<ApiResponse<GetExamListResponse>>()
4242
.document("테스트 리스트 조회 성공(200)") {
43-
responseBody(examListResponseFields)
43+
responseBody(getExamListResponseFields)
4444
}
4545
}
4646
}
4747

48-
describe("getMyExams(userId)는") {
49-
every { examQueryUseCase.getExamsByUserId(ID) } returns listOf(createExamResult())
48+
describe("getMyExams()는") {
49+
every { examQueryUseCase.getMyExams(ID) } returns listOf(createGetMyExamResult())
5050

51-
it("상태 코드 200과 ExamListResponse를 반환한다.") {
51+
it("상태 코드 200과 GetMyExamsListResponse를 반환한다.") {
5252
webClient
5353
.get()
5454
.uri("/api/v1/users/me/exams/solved")
5555
.exchange()
5656
.expectStatus()
5757
.isOk
58-
.expectBody<ApiResponse<ExamListResponse>>()
58+
.expectBody<ApiResponse<GetMyExamListResponse>>()
5959
.document("내가 푼 테스트 리스트 조회 성공(200)") {
60-
responseBody(examListResponseFields)
60+
responseBody(getMyExamListResponseFields)
6161
}
6262
}
6363
}
6464

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

6969
it("상태 코드 200과 ExamResponse를 반환한다.") {
7070
webClient
@@ -82,7 +82,7 @@ class ExamControllerTest : ControllerTest() {
8282
}
8383

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

8787
it("상태 코드 404와 ErrorResponse를 반환한다.") {
8888
webClient
@@ -100,7 +100,7 @@ class ExamControllerTest : ControllerTest() {
100100
}
101101
}
102102

103-
describe("getExamParticipantCount(examId)는") {
103+
describe("getExamParticipantCount()는") {
104104
every { examQueryUseCase.getExamParticipantCountById(ID) } returns PARTICIPANT_COUNT
105105

106106
it("상태 코드 200과 GetExamParticipantCountResponse를 반환한다.") {
@@ -175,24 +175,6 @@ class ExamControllerTest : ControllerTest() {
175175
}
176176
}
177177

178-
context("시작하지 않은 테스트를 제출하는 경우") {
179-
every { examCommandUseCase.submitExam(ID, ID) } throws ExamNotFoundException()
180-
181-
it("상태 코드 404와 ErrorResponse를 반환한다.") {
182-
webClient
183-
.post()
184-
.uri("/api/v1/exams/{examId}/submit", ID)
185-
.exchange()
186-
.expectStatus()
187-
.isNotFound
188-
.expectError()
189-
.document("테스트 제출 실패(404 - 1)") {
190-
pathParams("examId" desc "테스트 식별자")
191-
responseBody(errorResponseFields)
192-
}
193-
}
194-
}
195-
196178
context("시작하지 않은 테스트를 제출하는 경우") {
197179
every { examCommandUseCase.submitExam(ID, ID) } throws ExamHistoryNotFoundException()
198180

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

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.gotchai.api.docs
22

3-
import com.gotchai.api.presentation.v1.exam.response.ExamResponse
4-
import com.gotchai.api.presentation.v1.exam.response.GetExamParticipantCountResponse
5-
import com.gotchai.api.presentation.v1.exam.response.StartExamResponse
6-
import com.gotchai.api.presentation.v1.exam.response.SubmitExamResponse
3+
import com.gotchai.api.presentation.v1.exam.response.*
74
import com.gotchai.api.util.desc
85
import com.gotchai.api.util.fieldsOf
96
import com.gotchai.api.util.listFieldsOf
@@ -20,16 +17,44 @@ val examResponseFields =
2017
ExamResponse::iconImage desc "아이콘 이미지 URI",
2118
ExamResponse::coverImage desc "커버 이미지 URI",
2219
ExamResponse::theme desc "테마",
23-
ExamResponse::isSolved desc "테스트 풀이 여부",
2420
ExamResponse::createdAt desc "생성 날짜"
2521
)
2622

2723
val examListResponseFields =
2824
listFieldsOf(
29-
"list" desc "테스트 리스트",
25+
ExamListResponse::list desc "테스트 리스트",
3026
*examResponseFields.toTypedArray()
3127
)
3228

29+
val getExamResponseFields =
30+
fieldsOf(
31+
*examResponseFields.toTypedArray(),
32+
GetExamResponse::isSolved desc "테스트 완료 여부"
33+
)
34+
35+
val getExamListResponseFields =
36+
listFieldsOf(
37+
GetExamListResponse::list desc "테스트 리스트",
38+
*getExamResponseFields.toTypedArray()
39+
)
40+
41+
val getMyExamResponseFields =
42+
fieldsOf(
43+
GetMyExamResponse::id desc "식별자",
44+
GetMyExamResponse::title desc "제목",
45+
GetMyExamResponse::iconImage desc "아이콘 이미지 URI",
46+
GetMyExamResponse::correctAnswerRate desc "정답률",
47+
GetMyExamResponse::totalQuizCount desc "전체 퀴즈 개수",
48+
GetMyExamResponse::correctAnswerCount desc "맞춘 퀴즈 개수",
49+
GetMyExamResponse::solvedAt desc "테스트를 완료한 날짜"
50+
)
51+
52+
val getMyExamListResponseFields =
53+
listFieldsOf(
54+
GetMyExamListResponse::list desc "테스트 리스트",
55+
*getMyExamResponseFields.toTypedArray()
56+
)
57+
3358
val getExamParticipantCountResponseFields =
3459
fieldsOf(
3560
GetExamParticipantCountResponse::participantCount desc "참여자 수"

domain/src/main/kotlin/com/gotchai/domain/badge/adapter/in/BadgeQueryService.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.gotchai.domain.badge.adapter.`in`
22

3+
import com.gotchai.domain.badge.dto.projection.BadgeWithAcquiredAt
34
import com.gotchai.domain.badge.dto.result.GetMyBadgesResult
45
import com.gotchai.domain.badge.entity.Badge
56
import com.gotchai.domain.badge.entity.Tier
@@ -22,11 +23,11 @@ class BadgeQueryService(
2223

2324
@Transactional(readOnly = true)
2425
override fun getMyBadges(userId: Long): GetMyBadgesResult {
25-
val badges = badgeQueryPort.getBadgesWithAcquiredAtByUserId(userId)
26+
val badges = badgeQueryPort.getBadgesWithUserBadgeByUserId(userId)
2627
val examCount = examQueryPort.getExamCount()
2728

2829
return GetMyBadgesResult(
29-
badges = badges,
30+
badges = badges.map { BadgeWithAcquiredAt.of(it.badge, it.userBadge) },
3031
totalBadgeCount = examCount
3132
)
3233
}

0 commit comments

Comments
 (0)