Skip to content

Commit f78c761

Browse files
authored
test(submission): add domain layer tests (#117)
1 parent 922522e commit f78c761

File tree

2 files changed

+378
-1
lines changed

2 files changed

+378
-1
lines changed

src/test/java/org/ezcode/codetest/domain/language/service/LanguageDomainServiceTest.java renamed to src/test/java/org/ezcode/codetest/domain/language/LanguageDomainServiceTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.ezcode.codetest.domain.language.service;
1+
package org.ezcode.codetest.domain.language;
22

33
import static org.assertj.core.api.Assertions.*;
44
import static org.mockito.BDDMockito.*;
@@ -10,6 +10,7 @@
1010
import org.ezcode.codetest.domain.language.exception.code.LanguageExceptionCode;
1111
import org.ezcode.codetest.domain.language.model.entity.Language;
1212
import org.ezcode.codetest.domain.language.repository.LanguageRepository;
13+
import org.ezcode.codetest.domain.language.service.LanguageDomainService;
1314
import org.junit.jupiter.api.BeforeEach;
1415
import org.junit.jupiter.api.DisplayName;
1516
import org.junit.jupiter.api.Nested;
Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
package org.ezcode.codetest.domain.submission;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
import static org.mockito.BDDMockito.*;
5+
6+
import java.time.LocalDateTime;
7+
import java.util.List;
8+
import java.util.Optional;
9+
10+
import org.ezcode.codetest.application.submission.model.SubmissionContext;
11+
import org.ezcode.codetest.domain.language.model.entity.Language;
12+
import org.ezcode.codetest.domain.problem.model.entity.Problem;
13+
import org.ezcode.codetest.domain.submission.dto.WeeklySolveCount;
14+
import org.ezcode.codetest.domain.submission.model.SubmissionAggregator;
15+
import org.ezcode.codetest.domain.submission.model.SubmissionResult;
16+
import org.ezcode.codetest.domain.submission.model.TestcaseEvaluationInput;
17+
import org.ezcode.codetest.domain.submission.model.entity.Submission;
18+
import org.ezcode.codetest.domain.submission.model.entity.UserProblemResult;
19+
import org.ezcode.codetest.domain.submission.repository.SubmissionRepository;
20+
import org.ezcode.codetest.domain.submission.repository.UserProblemResultRepository;
21+
import org.ezcode.codetest.domain.submission.service.SubmissionDomainService;
22+
import org.ezcode.codetest.domain.user.model.entity.User;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.DisplayName;
25+
import org.junit.jupiter.api.Test;
26+
import org.junit.jupiter.api.extension.ExtendWith;
27+
import org.mockito.InjectMocks;
28+
import org.mockito.Mock;
29+
import org.mockito.junit.jupiter.MockitoExtension;
30+
31+
@ExtendWith(MockitoExtension.class)
32+
@DisplayName("제출 도메인 서비스 테스트")
33+
public class SubmissionDomainServiceTest {
34+
35+
@InjectMocks
36+
private SubmissionDomainService submissionDomainService;
37+
38+
@Mock
39+
private SubmissionRepository submissionRepository;
40+
41+
@Mock
42+
private UserProblemResultRepository userProblemResultRepository;
43+
44+
@Mock
45+
private SubmissionContext ctx;
46+
47+
@Mock
48+
private UserProblemResult userProblemResult;
49+
50+
@Mock
51+
private SubmissionAggregator aggregator;
52+
53+
@Mock
54+
private User user;
55+
56+
@Mock
57+
private Problem problem;
58+
59+
@Mock
60+
private Language language;
61+
62+
@Mock
63+
private TestcaseEvaluationInput input;
64+
65+
private Long userId;
66+
private Long problemId;
67+
private Long averageExecutionTime;
68+
private Long averageMemoryUsage;
69+
private String sourceCode;
70+
private String currentMessage;
71+
private int passedCount;
72+
private int testcaseCount;
73+
74+
@BeforeEach
75+
void setup() {
76+
userId = 1L;
77+
problemId = 1L;
78+
averageExecutionTime = 1000L;
79+
averageMemoryUsage = 12000L;
80+
sourceCode = "source-code";
81+
currentMessage = "current-message";
82+
passedCount = 10;
83+
testcaseCount = 10;
84+
}
85+
86+
@Test
87+
@DisplayName("처음 제출 -> 새로 저장하고 정답이면 correct count 증가")
88+
void firstSubmission_passed() {
89+
90+
// given
91+
given(ctx.user()).willReturn(user);
92+
given(user.getId()).willReturn(userId);
93+
94+
given(ctx.getProblem()).willReturn(problem);
95+
given(problem.getId()).willReturn(problemId);
96+
97+
given(ctx.language()).willReturn(language);
98+
given(ctx.getSourceCode()).willReturn(sourceCode);
99+
given(ctx.getCurrentMessage()).willReturn(currentMessage);
100+
given(ctx.getPassedCount()).willReturn(passedCount);
101+
given(ctx.getTestcaseCount()).willReturn(testcaseCount);
102+
103+
given(ctx.aggregator()).willReturn(aggregator);
104+
given(aggregator.averageExecutionTime()).willReturn(averageExecutionTime);
105+
given(aggregator.averageMemoryUsage()).willReturn(averageMemoryUsage);
106+
107+
given(ctx.getCategories()).willReturn(List.of());
108+
109+
given(ctx.isPassed()).willReturn(true);
110+
111+
given(userProblemResultRepository.findUserProblemResultByUserIdAndProblemId(userId, problemId))
112+
.willReturn(Optional.empty());
113+
given(userProblemResultRepository.saveUserProblemResult(any())).willReturn(userProblemResult);
114+
given(userProblemResult.getUser()).willReturn(user);
115+
116+
// when
117+
SubmissionResult submissionResult = submissionDomainService.finalizeSubmission(ctx);
118+
119+
// then
120+
then(submissionRepository).should().saveSubmission(any());
121+
then(ctx).should().incrementTotalSubmissions();
122+
then(ctx).should().incrementCorrectSubmissions();
123+
then(userProblemResultRepository).should().saveUserProblemResult(any());
124+
assertThat(submissionResult.isSolved()).isFalse();
125+
}
126+
127+
@Test
128+
@DisplayName("처음 제출 -> 새로 저장하고 오답이면 correct count 미증가")
129+
void firstSubmission_failed() {
130+
131+
// given
132+
given(ctx.user()).willReturn(user);
133+
given(user.getId()).willReturn(userId);
134+
135+
given(ctx.getProblem()).willReturn(problem);
136+
given(problem.getId()).willReturn(problemId);
137+
138+
given(ctx.language()).willReturn(language);
139+
given(ctx.getSourceCode()).willReturn(sourceCode);
140+
given(ctx.getCurrentMessage()).willReturn(currentMessage);
141+
given(ctx.getPassedCount()).willReturn(passedCount);
142+
given(ctx.getTestcaseCount()).willReturn(testcaseCount);
143+
144+
given(ctx.aggregator()).willReturn(aggregator);
145+
given(aggregator.averageExecutionTime()).willReturn(averageExecutionTime);
146+
given(aggregator.averageMemoryUsage()).willReturn(averageMemoryUsage);
147+
148+
given(ctx.getCategories()).willReturn(List.of());
149+
150+
given(ctx.isPassed()).willReturn(false);
151+
152+
given(userProblemResultRepository.findUserProblemResultByUserIdAndProblemId(userId, problemId))
153+
.willReturn(Optional.empty());
154+
given(userProblemResultRepository.saveUserProblemResult(any())).willReturn(userProblemResult);
155+
given(userProblemResult.getUser()).willReturn(user);
156+
157+
// when
158+
SubmissionResult submissionResult = submissionDomainService.finalizeSubmission(ctx);
159+
160+
// then
161+
then(submissionRepository).should().saveSubmission(any());
162+
then(ctx).should().incrementTotalSubmissions();
163+
then(ctx).should(never()).incrementCorrectSubmissions();
164+
then(userProblemResultRepository).should().saveUserProblemResult(any());
165+
assertThat(submissionResult.isSolved()).isFalse();
166+
}
167+
168+
@Test
169+
@DisplayName("이전 오답 기록 -> 정답이면 update & correct count 증가")
170+
void retryAfterWrong_passed() {
171+
172+
// given
173+
given(ctx.user()).willReturn(user);
174+
given(user.getId()).willReturn(userId);
175+
176+
given(ctx.getProblem()).willReturn(problem);
177+
given(problem.getId()).willReturn(problemId);
178+
179+
given(ctx.language()).willReturn(language);
180+
given(ctx.getSourceCode()).willReturn(sourceCode);
181+
given(ctx.getCurrentMessage()).willReturn(currentMessage);
182+
given(ctx.getPassedCount()).willReturn(passedCount);
183+
given(ctx.getTestcaseCount()).willReturn(testcaseCount);
184+
185+
given(ctx.aggregator()).willReturn(aggregator);
186+
given(aggregator.averageExecutionTime()).willReturn(averageExecutionTime);
187+
given(aggregator.averageMemoryUsage()).willReturn(averageMemoryUsage);
188+
189+
given(ctx.getCategories()).willReturn(List.of());
190+
191+
given(ctx.isPassed()).willReturn(true);
192+
193+
given(userProblemResult.isCorrect()).willReturn(false);
194+
given(userProblemResultRepository.findUserProblemResultByUserIdAndProblemId(userId, problemId))
195+
.willReturn(Optional.of(userProblemResult));
196+
given(userProblemResult.getUser()).willReturn(user);
197+
198+
// when
199+
SubmissionResult submissionResult = submissionDomainService.finalizeSubmission(ctx);
200+
201+
// then
202+
then(submissionRepository).should().saveSubmission(any());
203+
then(ctx).should().incrementTotalSubmissions();
204+
then(ctx).should().incrementCorrectSubmissions();
205+
then(userProblemResultRepository).should().updateUserProblemResult(userProblemResult, true);
206+
assertThat(submissionResult.isSolved()).isFalse();
207+
}
208+
209+
@Test
210+
@DisplayName("이전 오답 기록 -> 재제출 오답 시 update 미호출 & correct count 미증가")
211+
void retryAfterWrong_failedAgain() {
212+
213+
// given
214+
given(ctx.user()).willReturn(user);
215+
given(user.getId()).willReturn(userId);
216+
217+
given(ctx.getProblem()).willReturn(problem);
218+
given(problem.getId()).willReturn(problemId);
219+
220+
given(ctx.language()).willReturn(language);
221+
given(ctx.getSourceCode()).willReturn(sourceCode);
222+
given(ctx.getCurrentMessage()).willReturn(currentMessage);
223+
given(ctx.getPassedCount()).willReturn(passedCount);
224+
given(ctx.getTestcaseCount()).willReturn(testcaseCount);
225+
226+
given(ctx.aggregator()).willReturn(aggregator);
227+
given(aggregator.averageExecutionTime()).willReturn(averageExecutionTime);
228+
given(aggregator.averageMemoryUsage()).willReturn(averageMemoryUsage);
229+
230+
given(ctx.getCategories()).willReturn(List.of());
231+
232+
given(ctx.isPassed()).willReturn(false);
233+
234+
given(userProblemResult.isCorrect()).willReturn(false);
235+
given(userProblemResultRepository.findUserProblemResultByUserIdAndProblemId(userId, problemId))
236+
.willReturn(Optional.of(userProblemResult));
237+
given(userProblemResult.getUser()).willReturn(user);
238+
239+
// when
240+
SubmissionResult submissionResult = submissionDomainService.finalizeSubmission(ctx);
241+
242+
// then
243+
then(submissionRepository).should().saveSubmission(any());
244+
then(ctx).should().incrementTotalSubmissions();
245+
then(ctx).should(never()).incrementCorrectSubmissions();
246+
then(userProblemResultRepository).should(never())
247+
.updateUserProblemResult(any(UserProblemResult.class), anyBoolean());
248+
assertThat(submissionResult.isSolved()).isFalse();
249+
}
250+
251+
@Test
252+
@DisplayName("이전 정답 기록 -> 재제출 정답 시 update 미호출 & correct count 미증가")
253+
void retryAfterCorrect_passedAgain() {
254+
255+
// given
256+
given(ctx.user()).willReturn(user);
257+
given(user.getId()).willReturn(userId);
258+
259+
given(ctx.getProblem()).willReturn(problem);
260+
given(problem.getId()).willReturn(problemId);
261+
262+
given(ctx.language()).willReturn(language);
263+
given(ctx.getSourceCode()).willReturn(sourceCode);
264+
given(ctx.getCurrentMessage()).willReturn(currentMessage);
265+
given(ctx.getPassedCount()).willReturn(passedCount);
266+
given(ctx.getTestcaseCount()).willReturn(testcaseCount);
267+
268+
given(ctx.aggregator()).willReturn(aggregator);
269+
given(aggregator.averageExecutionTime()).willReturn(averageExecutionTime);
270+
given(aggregator.averageMemoryUsage()).willReturn(averageMemoryUsage);
271+
272+
given(ctx.getCategories()).willReturn(List.of());
273+
274+
given(ctx.isPassed()).willReturn(true);
275+
276+
given(userProblemResult.isCorrect()).willReturn(true);
277+
given(userProblemResultRepository.findUserProblemResultByUserIdAndProblemId(userId, problemId))
278+
.willReturn(Optional.of(userProblemResult));
279+
given(userProblemResult.getUser()).willReturn(user);
280+
281+
// when
282+
SubmissionResult submissionResult = submissionDomainService.finalizeSubmission(ctx);
283+
284+
// then
285+
then(submissionRepository).should().saveSubmission(any());
286+
then(ctx).should().incrementTotalSubmissions();
287+
then(ctx).should(never()).incrementCorrectSubmissions();
288+
then(userProblemResultRepository).should(never())
289+
.updateUserProblemResult(any(UserProblemResult.class), anyBoolean());
290+
assertThat(submissionResult.isSolved()).isTrue();
291+
}
292+
293+
@Test
294+
@DisplayName("통과된 테스트케이스일 때")
295+
void whenPassed() {
296+
297+
// given
298+
given(ctx.aggregator()).willReturn(aggregator);
299+
given(input.isCorrect()).willReturn(true);
300+
given(input.timeEfficient()).willReturn(true);
301+
given(input.memoryEfficient()).willReturn(true);
302+
303+
// when
304+
boolean passed = submissionDomainService.handleEvaluationAndUpdateStats(input, ctx);
305+
306+
// then
307+
assertThat(passed).isTrue();
308+
then(ctx).should().incrementPassedCount();
309+
then(ctx).should().incrementProcessedCount();
310+
then(aggregator).should().accumulate(input);
311+
then(ctx).should(never()).updateMessage(any());
312+
}
313+
314+
@Test
315+
@DisplayName("실패한 테스트케이스일 때")
316+
void whenFailed() {
317+
318+
// given
319+
given(ctx.aggregator()).willReturn(aggregator);
320+
given(input.isCorrect()).willReturn(true);
321+
given(input.timeEfficient()).willReturn(false);
322+
given(input.memoryEfficient()).willReturn(true);
323+
given(input.resultMessage()).willReturn(currentMessage);
324+
325+
// when
326+
boolean passed = submissionDomainService.handleEvaluationAndUpdateStats(input, ctx);
327+
328+
// then
329+
assertThat(passed).isFalse();
330+
then(ctx).should(never()).incrementPassedCount();
331+
then(ctx).should().incrementProcessedCount();
332+
then(aggregator).should().accumulate(input);
333+
then(ctx).should().updateMessage(currentMessage);
334+
}
335+
336+
@Test
337+
@DisplayName("userId에 맞는 제출 목록을 레포지토리에서 가져와 반환")
338+
void getSubmissions_returnListFromRepository() {
339+
340+
// given
341+
Submission s1 = mock(Submission.class);
342+
Submission s2 = mock(Submission.class);
343+
List<Submission> mockList = List.of(s1, s2);
344+
345+
given(submissionRepository.findSubmissionsByUserId(userId)).willReturn(mockList);
346+
347+
// when
348+
List<Submission> result = submissionDomainService.getSubmissions(userId);
349+
350+
// then
351+
then(submissionRepository).should().findSubmissionsByUserId(userId);
352+
assertThat(result).isSameAs(mockList);
353+
}
354+
355+
@Test
356+
@DisplayName("기간에 따른 주간 통계 목록을 레포지토리에서 가져와 반환")
357+
void getWeeklySolveCounts_returnListFromRepository() {
358+
359+
// given
360+
LocalDateTime start = LocalDateTime.of(2025, 6, 23, 0, 0);
361+
LocalDateTime end = LocalDateTime.of(2025, 6, 29, 23, 59);
362+
363+
WeeklySolveCount w1 = mock(WeeklySolveCount.class);
364+
WeeklySolveCount w2 = mock(WeeklySolveCount.class);
365+
List<WeeklySolveCount> mockList = List.of(w1, w2);
366+
367+
given(submissionRepository.fetchWeeklySolveCounts(start, end)).willReturn(mockList);
368+
369+
// when
370+
List<WeeklySolveCount> result = submissionDomainService.getWeeklySolveCounts(start, end);
371+
372+
// then
373+
then(submissionRepository).should().fetchWeeklySolveCounts(start, end);
374+
assertThat(result).isSameAs(mockList);
375+
}
376+
}

0 commit comments

Comments
 (0)