JAVA/JAVA | Spring 학습기록

[Spring] JUnit5 에서 OutputCapture를 이용한 로그 테스트 해보기

kth990303 2024. 4. 30. 16:15
반응형

최근에 우연히 로그를 테스트하는 방법에 대해 알게돼서 기록용으로 남겨보려 한다.

바로 Spring Boot 에서 제공해주는 OutputCaptureExtension 이다.

 

OutputCapture

 

Spring Boot 2.2.0 이상의 환경이라면 gradle에 별도의 추가설정 없이 사용이 가능하다.

안내돼있는 것처럼, System.out, System.err 로 출력되는 코드들을 캡처해서 AssertJ, JUnit 테스트에서 로그 출력 여부를 확인할 수 있다.

 

참고로 @Slf4j 의 log.info, log.error 로그 출력 캡처도 가능하다.

따라서 Java, Kotlin의 웬만한 환경에서는 다 사용이 가능하리라 생각한다.


테스트

회원가입 (signUp 메서드)을 진행하면 아래 코드와 같이 log.info 로 회원가입 로그를 찍는다. 

 

프로덕션 코드

1
2
3
4
5
6
@Transactional
public MemberSignResponse signUp(String username, String password) {
    Member member = memberRepository.save(new Member(username, password));
    log.info("회원가입 로그: {}", username);
    return new MemberSignResponse(member.getId());
}
cs

 

 

이 메서드가 호출될 때, 아래 테스트를 진행해보려 한다.

  • 회원가입 로그가 남는지
  • 어떤 username의 유저가 회원가입했는지

 

@ExtendWith 로 OutputCaptureExtension.class 를 import 해주었다.

OutputCaptureRule을 new 키워드로 선언해준 후, @Rule 어노테이션을 붙여주는 방법도 되긴 하지만. 나는 @ExtendWith 붙여주는 게 더 편하다고 생각한다.

 

테스트 코드

1
2
3
4
5
6
7
8
9
@Test
@DisplayName("회원가입 시 로그가 남는지 확인한다.")
void signUpWithLog(CapturedOutput output) {
    String username = "kth990303";
    String password = "1234";
    memberService.signUp(username, password);
 
    assertThat(output.getOut()).contains("회원가입 로그: " + username);
}
cs

 

위와 같이 테스트 코드를 작성하여, JUnit 문법으로 로그가 남는지 확인한다.

 

테스트 메서드의 파라미터로 CapturedOutput 변수를 선언해준 후,

실행할 메서드를 실행시킨 후

output.getOut() 에 우리가 원하는 로그가 포함(contains)되는지 확인하는 코드를 작성해주었다.

공식문서에서도 contains 를 체크하길 권장하고 있다.

 

결과

 

 

참고로, contains가 아닌 isEqualTo 를 사용한다면?

테스트 실패

 

테스트가 실패한다.

CapturedOutput 은 해당 테스트가 수행되기 시작하는 시점 (스프링 애플리케이션 테스트 컨텍스트 시작) 부터 캡처를 진행하는 것으로 보인다. 따라서 isEqualTo 가 아닌 contains로 테스트를 수행하는 것이 좋을 듯.


주의점

log.error()인 경우는 output.getErr() 대상이 아닌 output.getOut() 대상에 포함된다.

 

위와 같이 log.error 로 찍었다고 해서 System.err 로 남는 것은 아니다.

실제로 예외가 발생해서 System.err 에서 사용되는 버퍼에 있는 대상이 getErr()의 대상이 되는 것.

개발하다가 가끔 헷갈릴 수 있으니 주의할 것.

 

근데 테스트를 할 정도로 중요한 로그면 웬만해선 log.error, log.info 로도 남길테니 사실상 getOut() 으로 거의 커버되지 않을까 싶다.

 

 

 

반응형