반응형
패캠 강의를 보며 일단 따라쳤지만, 제대로 이해하지 않으면 나중에 이상하게 사용할 것 같아 정리
- 요즘 단위테스트는 given-when-then 패턴으로 작성하는 추세이다 (참고)
- given : 어떤 데이터가 준비되었을 때
- when : 어떤 함수를 실행하면
- then : 어떤 결과가 나와야 한다
// TodoServiceTest.java
@Test
void add() {
when(this.todoRepository.save(any(TodoEntity.class)))
.then(AdditionalAnswers.returnsFirstArg());
TodoRequest expected = new TodoRequest();
expected.setTitle("Test Title");
TodoEntity actual = this.todoService.add(expected);
assertEquals(expected.getTitle(), actual.getTitle());
}
- given
- when : todoRepository.save 함수를 실행하면
- then : 받은 첫번째 인자를 바로 반환 (mockito 라이브러리)
- 이후 다시 given : "Test Title"이라는 title을 가진 expected 인스턴스가 준비되었을때
- when : todoService.add(expected) 함수를 실행하면
- add -> todoRepository.save로 작용, 인자 그대로 반환하며 actual에 expected와 동일한 데이터 담김
- then(assertEquals) : expected와 actual의 title이 동일
// TodoServiceTest.java
@Test
void searchById() {
TodoEntity entity = new TodoEntity();
entity.setId(123L);
entity.setTitle("TITLE");
entity.setOrder(0L);
entity.setCompleted(false);
Optional<TodoEntity> optional = Optional.of(entity);
given(this.todoRepository.findById(anyLong()))
.willReturn(optional);
TodoEntity actual = this.todoService.searchById(123L);
TodoEntity expected = optional.get();
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getTitle(), actual.getTitle());
assertEquals(expected.getOrder(), actual.getOrder());
assertEquals(expected.getCompleted(), actual.getCompleted());
}
- Optional은 null 참조를 사용하는 대신 안전한 대안을 제공하도록 설계된 Java 8 클래스 (ChatGPT의 답변..)
- given
- anyLong으로 todoRepository.findById 함수를 호출하면 optional 인스턴스가 return됨
- expected는 optional.get
- when : todoService.searchById를 호출하면
- todoService.searchById -> todoRepository.findById 적용되면서 actual에 optional과 같은 데이터
- then: id, title, order, completed가 모두 같아야함
- 지금 보니 actual이 expected 아래에 있는게 given-when-then 순서에 조금 더 가까운 것 같다
// TodoServiceTest.java
@Test
public void searchByIdFailed(){
given(this.todoRepository.findById(anyLong()))
.willReturn(Optional.empty());
assertThrows(ResponseStatusException.class, () -> {
this.todoService.searchById(123L);
});
}
- todoRepository.findById가 항상 empty를 return
- todoService.searchById -> todoRepository.findById로 작동하며 empty return. NOT_FOUND 에러 발생하며 assertThrows 성공
// TodoControllerTest.java
@Test
void create() throws Exception{
when(this.todoService.add(any(TodoRequest.class)))
.then((i) -> {
TodoRequest request = i.getArgument(0, TodoRequest.class);
return new TodoEntity(
this.expected.getId(),
request.getTitle(),
this.expected.getOrder(),
this.expected.getCompleted());
});
TodoRequest request = new TodoRequest();
request.setTitle("ANY TITLE");
ObjectMapper mapper = new ObjectMapper();
String content = mapper.writeValueAsString(request);
this.mvc.perform(post("/").contentType(MediaType.APPLICATION_JSON).content(content))
.andExpect(status().isOk())
.andExpect(jsonPath("$.title").value("ANY TITLE"));
}
- todoService.add 호출 시 그대로 반환
- ObjectMapper와 mvc.perform 사용해서 post요청 전송 -> Ok와 title이 ANY TITLE이면 성공
Service쪽 정리하면서 개념이 이해됐다.
ControllerTest는 정말 이해하기 어려웠는데 지금은 어느정도 이해가 간다.
TDD를 습관화하자 ㅎㅎ
반응형