이 게시글은 이동욱 - "스프링 부트와 AWS로 혼자 구현하는 웹 서비스" 에서 참고하였습니다.
위 책을 참고하여 JUnit 에서 값을 등록하는 테스트를 만들어보았습니다.
문제 상황
JUnit 을 수행하는 과정에서 posts api 까지 정상적으로 값이 전달되지만 NullPointerException 에러가 발생
■ PostsApiControllerTest.java
@Test
public void Posts_등록된다() throws Exception {
//given
String title = "title";
String content = "content";
PostsSaveRequestDto requestDto = PostsSaveRequestDto.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
//when
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDto, Long.class);
//then
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);
assertThat(all.get(0).getContent()).isEqualTo(content);
}
■ PostsSaveRequestDto.java
@Getter
@NoArgsConstructor
public class PostsSaveRequestDto {
private String title;
private String content;
private String author;
@Builder
public PostsSaveRequestDto(String title, String content, String author){
this.title = title;
this.content = content;
this.author = author;
}
public Posts toEntity(){
return Posts.builder()
.title(title)
.content(content)
.author(author)
.build();
}
}
■ PostsApiController.java
@RequiredArgsConstructor
@RestController
public class PostsApiController {
private PostsService postsService;
@PostMapping("/api/v1/posts")
public Long save(@RequestBody PostsSaveRequestDto requestDto){
return postsService.save(requestDto);
}
}
위 코드를 베이스로 Test를 수행하면 아래와같은 NullPointerException 에러가 발생합니다.
문제 해결
해당 캐이스에 대해서 원인을 파악해보니 save 메서드에서 postsService를 사용할 때 외부에서 가져오는것이 아닌 PostsApiController 에서 새로 선언하여 가져왔기 때문에 null 값을 가지고 오고 있었습니다.
예를 들어, PostsApiController가 PostsService의 메소드를 호출하여 작업을 수행한다고 가정해봅시다. PostsApiController가 직접 PostsService의 인스턴스를 생성하면, 두 클래스 사이의 결합도가 높아집니다. 이로 인해 PostsService의 변경이 PostsApiController에도 영향을 미칠 수 있고, 테스트하기 어려워집니다.
의존성 주입을 사용하면, PostsService의 인스턴스를 PostsApiController 외부에서 생성하고 이를 PostsApiController에 주입합니다. 이렇게 하면 PostsApiController는 PostsService의 구현 세부 사항을 알 필요가 없으며, 다른 PostsService 구현으로 쉽게 교체할 수 있게 됩니다.
제공된 코드에서 PostsService 필드는 초기화되지 않았습니다.
즉, PostsService의 인스턴스가 생성되어 PostsApiController에 주입되지 않았기 때문에, postsService는 기본값인 null을 가집니다. 그런 다음 save 메소드에서 postsService.save(requestDto);를 호출하려고 하면, 실제로 null.save(requestDto);를 호출하려고 시도하는 것과 같습니다. 자바에서는 null에 대해 메소드를 호출하려고 하면 NullPointerException이 발생합니다.
수정된 코드
코드 수정 후 정상 동작 확인!
결론
NullPointerException 에러가 발생했을 때 데이터가 비어있는 부분을 찾지 못했다면 DI를 빼먹은 부분이 있는지 의심해보자!
'개발지식' 카테고리의 다른 글
[Vue.js] vue create [파일명] 보안 오류 해결 (2) | 2024.04.16 |
---|---|
[클라우드] IaaS vs PaaS vs SaaS 에 대하여! (2) | 2024.03.25 |
닷넷(.net) 이란?! (2) | 2024.03.21 |
이벤트 기반 아키텍처 (feat. 배달의민족 마이크로서비스 여행기) (2) | 2024.03.19 |
스프링 웹 계층에 대하여.. (2) | 2024.03.18 |