Spring Boot Test - Service 테스트
JUnit 5, Mockito와 함께하는 Service 코드 테스트!
잊어버리지 않기 위해 기록 ✏️
Service 코드가 다음 형태로 구현되어 있을 때,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@RequiredArgsConstructor
@Service
public class TaskService {
private final TaskRepository taskRepository;
private final TaskConverter taskConverter;
public List<TaskResponse> todayPlan(long userId) {
var taskEntityList = getTaskEntityListWithThrow(userId);
return taskEntityList.stream()
.map(taskConverter::toResponse)
.toList();
}
public List<TaskEntity> getTaskEntityListWithThrow(long userId) {
var taskEntityList = taskRepository.findAllByUserIdAndStartedAt_DateAndCompletedAtIsNotNullOrderByStartedAtAsc(
userId, LocalDateTime.now()
);
if (taskEntityList.isEmpty()) {
throw new ApiException("task is empty");
}
return taskEntityList;
}
}
test 코드 작성
mocking을 통한 service 로직 검증을 목표로 테스트 코드를 작성한다.
로직의 결과를 예상하여 stubbing 후 service 메서드를 실행하여 예상 한 결과로 응답이 떨어지는지 확인하면 된다.!
Mock 관련 어노테이션(@Mock, @InjectMocks 등)을 사용하기 위해 @ExtendWith(MockitoExtension.class)
를 추가해주어야 한다.
- @InjectMocks : 실행 할 클래스(ex. TaskService.java)에 Mock 객체를 주입
- @Spy : 해당 객체를 Mock 객체로 생성. Stubbing 하지 않은 메서드는 원본 메서드가 실행되도록 해줌
- @Mock : 해당 객체를 Mock 객체로 생성. Stubbing 하지 않은 메서드는 null이 되어 실행시 null pointer exception 발생
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
@ExtendWith(MockitoExtension.class)
class TaskServiceTest {
@InjectMocks TaskService service;
@Mock TaskRepository repository;
@Spy TaskConverter converter;
@DisplayName("task list 조회 - 오늘 날짜 데이터 없음")
@Test
void todayPlan_is_empty() {
// given
BDDMockito
.given(repository
.findAllByUserIdAndStartedAt_DateAndCompletedAtIsNotNullOrderByStartedAtAsc(
anyLong(), any(LocalDateTime.class)
))
.willReturn(List.of());
// when - then
Assertions.assertThrows(
ApiException.class,
() -> service.todayPlan(1L),
"task is empty"
);
BDDMockito
.then(repository)
.should(Mockito.times(1))
.findAllByUserIdAndStartedAt_DateAndCompletedAtIsNotNullOrderByStartedAtAsc(
anyLong(), any(LocalDateTime.class)
);
BDDMockito
.then(service)
.should(Mockito.times(1))
.getTaskEntityListWithThrow(anyLong());
BDDMockito
.then(converter)
.should(Mockito.times(0))
.toResponse(any(TaskEntity.class));
}
@DisplayName("task list 조회 - 오늘 날짜 데이터 있음")
@Test
void todayPlan_list() {
// given
long userId = 1L;
List<TaskEntity> taskEntityList = List.of(
getTaskEntity(
1L, userId,
"java - stream",
"stream 실습"
),
getTaskEntity(
2L, userId,
"DB - MySQL",
"Docker MySQL 설치, 프로젝트와 연결해보는 실습"
)
);
BDDMockito
.given(repository
.findAllByUserIdAndStartedAt_DateAndCompletedAtIsNotNullOrderByStartedAtAsc(
eq(userId), any(LocalDateTime.class)
))
.willReturn(taskEntityList);
List<TaskResponse> doReturnTaskResponses = taskEntityList.stream()
.map(converter::toResponse)
.toList();
// when
List<TaskResponse> actualTaskResponses = service.todayPlan(userId);
// then
BDDMockito
.then(repository)
.should(Mockito.times(1))
.findAllByUserIdAndStartedAt_DateAndCompletedAtIsNotNullOrderByStartedAtAsc(
anyLong(), any(LocalDateTime.class)
);
BDDMockito
.then(converter)
.should(Mockito.atLeastOnce())
.toResponse(any(TaskEntity.class));
assertThat(doReturnTaskResponses)
.usingRecursiveComparison()
.isEqualTo(actualTaskResponses);
}
private static TaskEntity getTaskEntity(
long id, long userId, String title, String description
) {
return TaskEntity.builder()
.id(id)
.userId(userId)
.title(title)
.description(description)
.startedAt(LocalDateTime.now())
.build();
}
}
참고한 사이트
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.