Actuator 와 테스트 코드 그리고 Mail

잘 되던 테스트 코드 Actuator 의존성 추가 이후 실패!

Featured image

Actuator 의존성 추가.. 그리고 실패하는 테스트 코드

잘 실행되던 테스트 코드가 actuator 의존성을 추가하고 나서 실패한다.

implementation 'org.springframework.boot:spring-boot-starter-actuator'

스프링 컨테이너가 제대로 안 띄워지고 아래의 로그를 확인할 수 있는데 Acuator 의존성을 제거하면 테스트 코드는 잘 통과된다.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mvcHandlerMappingIntrospector' defined in class path resource... //...생략

비즈니스 로직 중 SMTP 서버를 통해 메일을 보내는 로직이 있다.

implementation 'org.springframework.boot:spring-boot-starter-mail'

Actuator 그리고 Mail health

Actuator 가 애플리케이션 컨텍스트를 로드할 때 Mail 관련 빈을 생성하지 않도록 해야 한다. 이를 통해 Mail 설정이 올바르게 되지 않거나 필요한 리소스가 누락되었을 때 빈을 생성하지 않도록 한다.

…가 아니라 MailHealthIndicator 빈이 제대로 생성되지 않을까? 메일을 보내는 설정과 관련해서 오류가 있는지 찾아보는 게 우선이다.🫨

의존성을 끊고 테스트를 통과하는게 우선이라면 테스트 코드에서 실행할 yml 에 다음과 같이 추가하면 된다. 메일 외에도 Actuator 로 방해받고 싶지 않다면 false 로 급하게 통과시킬 수 있다.

management:  
  endpoints:  
    enabled-by-default: false # 기본적으로 모든 Actuator 앤드포인트 비활성화  
    web:  
      exposure:  
        include: none # 웹을 통한 모든 Actuator 앤드포인트 비활성화  
  health:  
    mail:  
      enabled: false # Mail 헬스 체크 비활성화  
    enabled: false # 모든 헬스 체크 비활성화  
  info:  
    enabled: false # 애플리케이션 정보 앤드포인트 비활성화

MailHealthIndicator

Spring Boot Actuator 에서 제공하는 Healthindicator 의 구현체 중 하나로 메일 서버의 상태를 모니터링하는 역할을 수행한다. 실제 메일 서버와 연결하여 상태를 확인하기 때문에 테스트 관련해서 실패할 수도 있다.

위를 토대로 MailHealthIndicator의 간단한 단위 테스트 코드다.

@SpringBootTest  
public class MailHealthIndicatorTest {  
    @Autowired  
    private MailHealthIndicator mailHealthIndicator;  
  
    @Test  
    void mailHealth() {  
        final Health health = mailHealthIndicator.health();
        Assertions.assertThat(health.getStatus()).isEqualTo(Status.UP);  
    }  
}

위의 테스트 코드는 잘 통과과 되었으므로 아래의 SMTP 관련 yml 은 문제가 없다.

spring:  
  mail:  
    host: # 호스트
    port: 465 # (일반적으로 SSL을 사용하는 SMTP 서버의 포트)
    username: # 인증할 사용자 이름
    password: # 인증할 비밀번호
    default-encoding: UTF-8 # 기본 인코딩
    properties:  
      mail:  
        smtp:  
          auth: true # SMTP 서버에 로그인 인증을 시도하는가?
          ssl:  
            enable: true # SSL 을 사용하여 이메일을 전송하는가?
            trust: # 호스트, 특정 호스트의 SSL 인증서를 신뢰하는가?
          timeout: 15000 # 서버 연결 타임아웃
          quitwait: false # SMTP 서버가 연결을 종료할 때까지 기다릴 것인가?

그럼 무엇이 문제였을까?

테스트 코드에 결함이 하나 있었는데 JavaMailSender 를 mock 객체로 주입 받고 있었던 것이다.

@MockBean  
protected JavaMailSender javaMailSender;

Actuator 는 실제 메일 서버에 접근하여 health 정보를 가져오는데 목객체로 주입을 받으니 실제 서버와 연결할 수 없어 테스트 코드가 실패했던 것이다. restdocs 작성을 위한 테스트에서는 공통 코드들을 하나의 클래스에서 관리하고 상속하여 구현하는데 JavaMailSender 를 목객체로 주입을 받으니 해당 클래스가 테스트에 실패했던 것이다. 빠른 개발도 좋지만 시간이 더 걸리더라도 올바른 구현을 해야한다. 오히려 시간이 더 소모되기에.. 임시 방편으로 해결했던 Mail 관련 헬스 체크를 모두 꺼준 default 설정으로도 테스트 코드를 통과할 수 있다.