번외1 - 이메일 통합 테스트 하기

미립·2022년 7월 29일
0
post-custom-banner

JUnit5와 GreenMail을 사용하여 이메일이 정상적으로 수신되는지 테스트 하는법을 소개한다.

이메일 발송

Spring에서 SMTP를 사용하여 이메일을 보내는 기능은 주제에 벗어나므로 간단하게 소개한다.
자세한 내용이 궁금하면 검색을 이용하기를 바란다.

JavaMailsender를 이용하여 Gmail을 통해 이메일을 발송하도록 구현하였다.

SmtpEmailConfig.kt

@Configuration
class SmtpEmailConfig {

    @Value("\${spring.mail.transport.protocol}")
    lateinit var protocol: String
    @Value("\${spring.mail.properties.mail.smtp.auth}")
    private var auth : Boolean = false
    @Value("\${spring.mail.properties.mail.smtp.starttls.enable}")
    private var starttls : Boolean = false
    @Value("\${spring.mail.debug}")
    private var debug : Boolean = false
    @Value("\${spring.mail.host}")
    private lateinit var host: String
    @Value("\${spring.mail.port}")
    private var port : Int = 0
    @Value("\${spring.mail.username}")
    private lateinit var username: String
    @Value("\${spring.mail.password}")
    private lateinit var password: String
    @Value("\${spring.mail.default-encoding}")
    private lateinit var encoding: String

    @Bean
    fun javaMailSender() : JavaMailSender {
        val sender = JavaMailSenderImpl()
        val properties = Properties()
        properties["mail.transport.protocol"] = protocol
        properties["mail.smtp.auth"] = auth
        properties["mail.smtp.starttls.enable"] = starttls
        properties["mail.smtp.debug"] = debug

        sender.host = host
        sender.username = username
        sender.password = password
        sender.port = port
        sender.javaMailProperties = properties
        sender.defaultEncoding = encoding
        return sender
    }
}

SmtpMailSender.kt

@Component
class SmtpMailSender(private val sender : JavaMailSender) : MailSender {

    override fun send(to: String, subject: String, content: String) {
        val message = SimpleMailMessage()
        with(message) {
            setTo(to)
            setSubject(subject)
            setText(content)
        }
        sender.send(message)
    }
}

테스트 코드 작성

GreenMail을 사용하기 위한 의존성을 추가한다.

testImplementation("com.icegreen:greenmail-junit5:1.6.0")

우리는 이메일 발송만을 테스트할 예정이기 때문에 SMTP만 사용하도록 하였고 Junit5의 확장 기능중 @RegisterExtension 을 활용하여 메일 서버를 실행하여 테스트할 수 있도록 하였다.

@JvmField
@RegisterExtension
static GreenMailExtension greenMail = new GreenMailExtension(ServerSetupTest.SMTP)
  .withConfiguration(GreenMailConfiguration.aConfig().withUser("seok2", "1q2w3e!!"))
  .withPerMethodLifecycle(false);

이 코드를 통하여 GreenMail이 샌드박스 환경에서 실행되어 독립적인 테스트가 가능하도록 한다.
withPerMethodLifecycle 옵션을 통하여 재사용 여부를 결정하는데 사용되며 테스트를 독립적으로 구성하는데 활용할 수 있다.

이제 SmtpEmailConfig에 TestProperty 값을 넣어주면 샌드박스로 이메일을 수신할 수 있다.
깃헙액션을 사용하여 자동화된 테스트를 할 경우 설정값의 이메일정보의 노출을 막기위한 추가 작업이 필요하지만 GreenMail을 사용하면서 그런 번거로움도 사라졌다.

spring:
  mail:
    host: 127.0.0.1
    port: 3025
    username: seok2
    password: welcome
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
    transport:
      protocol: smtp
    debug: true
    default-encoding: UTF-8

테스트 전체 코드는 아래와 같다.

SmtpMailSenderTest.kt

@TestPropertySource(locations = ["/application.yml"])
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
internal class SmtpMailSenderTest(
    @Autowired
    private val sender: MailSender
) {

    companion object {
        @JvmField
        @RegisterExtension
        val smtp: GreenMailExtension = GreenMailExtension(ServerSetupTest.SMTP)
            .withConfiguration(GreenMailConfiguration.aConfig().withUser("seok2", "welcome"))
            .withPerMethodLifecycle(false)
    }

    @Test
    fun `이메일 발송 테스트`() {
        val content = "Have a good day"
        val to = "seok2@spring.io"

        sender.send(to, "Hello Green Mail", content)
        smtp.waitForIncomingEmail(1) // 비동기로 동작하기 떄문에 대기하도록 하였다.
        
        val received = smtp.receivedMessages[0]
        assertThat(GreenMailUtil.getBody(received)).isEqualTo(content)
        assertThat(received.allRecipients[0].toString()).isEqualTo(to)
    }

}

위 예제의 사용한 소스 코드는 GitHub에서 확인할 수 있습니다.

profile
software engineer
post-custom-banner

0개의 댓글