원글 페이지 : 바로가기

❗️에러 메시지 java.lang.AssertionError: Expecting actual not to be null 💻 개발 환경 Framework : Spring Boot `3.2.3` DB : MySQL(로컬), H2(테스트) Library : JPA, QueryDSL `5.0.0` Test : JUnit 🔎 원인 Spring에서 Junit으로 Service 단의 게시글 등록 기능을 테스트하는데 에러가 났다. 게시글 등록 메소드는 `save()`를 수행하고, 새로 등록된 게시글의 `id`를 반환한다. 이를 테스트하기 위해 Mock 객체를 만들어 `save()`를 수행하면 반환하도록 했고, `getId()`를 호출하면 `id`로 1L을 반환하도록 설정했다. 그리고 게시글 등록 메소드를 실행했을 때 반환값이 설정한 `id` 값과 같은지를 검증하는 코드를 작성했다. @Test
@DisplayName(“구직 게시글 생성”)
public void createHiringPostTest() {
// given
HiringPostReq hiringPostReq = HiringPostReq.builder()
…
.build();
…
HiringPost mockHiringPost = mock(HiringPost.class);
when(hiringPostRepository.save(any(HiringPost.class))).thenReturn(mockHiringPost);
when(mockHiringPost.getId()).thenReturn(1L);
// when
Long resultId = hiringPostServiceImpl.registerHiringPost(hiringPostReq);
//객체 확인을 위한 print
HiringPost savedHiringPost = hiringPostRepository.save(any(HiringPost.class));
System.out.println(“hiringPost: ” + savedHiringPost);
System.out.println(“resultId: ” + resultId);
// then
assertThat(resultId).isNotNull();
assertThat(resultId).isEqualTo(1L);
…
verify(hiringPostRepository, times(1)).save(any(HiringPost.class));
} 제대로 `save()`와 `getId()` 메소드가 실행되었는지 확인하기 위해서 프린트를 찍어봤다. `save()`가 호출되면 결과값으로 `null`이 나왔고, `getId()`를 호출하는 서비스 메소드 결과값인 `resultId`가 null이 나왔다. 서비스에서 `save()`가 호출될 때, Mockito가 Mock 객체(mockHiringPost)를 반환하지 않는 것이다. 서비스 메소드의 내부에서 새로 생성된 객체(HiringPost)를 반환한다. Mock 객체와 실제 객체가 혼용이 되고 있었다.. (지금 포스팅을 쓰는 순간에도 헷갈린다😅) 💡 해결 `save()`가 호출될 때, Mock 객체가 아니라 실제 객체가 사용되도록 한다. 그리고 실제 객체의 id 값을 설정해준다. when(hiringPostRepository.save(any(HiringPost.class))).thenAnswer(invocation -> {
HiringPost hiringPost = invocation.getArgument(0);
ReflectionTestUtils.setField(hiringPost, “id”, 1L);
return hiringPost;
}); 동작을 더 상세히 정의하기 위해서 `thenAnswer`을 사용한다. `invocation`은 메소드를 호출할 때, 반환값을 가져와 동작을 설정할 수 있도록 해준다. `invocation.getArgument(0)`의 결과로 저장하려는 HiringPost 객체를 가져오게 된다. 자동으로 id가 생성되지 않기 때문에 직접 id를 설정해줘야 한다. id 설정 부분에서 `ReflectionTestUtils`을 사용해야 했다. 객체의 필드가 private으로 정의되어 있기도 하고, 외부에서 값을 변경할 수 없도록 setter 사용을 막았기 때문이다. 📖 참고 https://velog.io/@win-luck/Springboot-%EC%8A%A4%ED%94%84%EB%A7%81-JUnit5%EC%97%90%EC%84%9C-Mockito%EB%A1%9C-Service-Layer-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0 ChatGPT