본문 바로가기
Java & Kotlin/Spring

Start Spring Data MongoDB - 5. Integration Test

by devson 2021. 9. 4.

테스트 코드의 중요성을 알아도 외부 인프라스트럭쳐와 연동해야하는 경우 테스트 자동화를 하기가 매우 까다로워진다.

다행히 Java 진영에서는 Testcontainers를 사용하면 통합 테스트 시 외부 인프라스트럭쳐를 손쉽게 구성할 수 있을 수 있다.

 

이번 포스팅에서는 Testcontainers의 MongoDB Module을 사용하여 통합 테스트 환경을 구축하고 통합 테스트 코드를 작성하는 방법에 대해 알아보도록 하겠다.

 

(관련 코드는 여기에서 확인 가능하다)


 

Testcontainers MongoDB Module dependency 추가

Testcontainers MongoDB Module은 MongoDB Transaction 테스트를 도와주기 위한 Module이다.

이를 통해 좀 더 쉽게 MongoDB Transaction 테스트를 할 수 있는데 앞으로 진행하면서 알아보도록 하자.

 

build.gradle.kt에 dependency를 추가한다.

https://mvnrepository.com/artifact/org.testcontainers/mongodb

dependencies {
    testImplementation("org.testcontainers:mongodb:1.16.0") // 추가
}

 

 

Testcontainers MongoDB Module세팅

기본 Spring Boot ApplicationTests에 MongoDB Module 설정을 하도록 하겠다.

 

companion object에 MongoDBContainer를 할당하고,

static으로써 DynamicPropertyRegistry에 Spring Data MongoDB property를 지정하도록 한다.

import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.MongoDBContainer

@SpringBootTest
class SpringMongoApplicationTests {
    companion object {
        private val mongodbContainer = MongoDBContainer("mongo:4.4").apply {
            this.start()
        }

        @JvmStatic
        @DynamicPropertySource
        fun registerProperties(registry: DynamicPropertyRegistry) {
            registry.add("spring.data.mongodb.uri", mongodbContainer::getReplicaSetUrl)
        }
    }

    @Test
    fun contextLoads() {
    }
}

 

이러면 기본적으로 MongoDB 연동 설정은 끝난 것이다.

 

위 테스트를 실행시키면 테스트 시 MongoDB 연동이 잘 이뤄져 Spring Context 생성 후 테스트가 통과되는 것을 확인할 수 있다.

 


org.testcontainers.containers.MongoDBContainer에 대해 부연설명을 하자면,

Testcontainers에서 MongoDB Transaction을 테스트하기 쉬운 환경을 제공하기 위한 Container 객체이다.

 

MongoDBContainer 클래스의 주석에 다음과 같이 Transaction을 테스트하기 위해 single node replica set을 구축한다고 적혀있으며

 

코드 내부적으로도 다음과 같이 replica set을 설정하는 것을 확인할 수 있다.


 

Transaction 테스트 추가

연동은 셋업하였으니 본격적으로 테스트 코드를 추가 후 실행시켜보자.

import com.tistory.devs0n.springmongo.content.domain.ContentRepository
import com.tistory.devs0n.springmongo.content.domain.ContentType
import com.tistory.devs0n.springmongo.content.service.ContentService
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.MongoDBContainer

@SpringBootTest
class SpringMongoApplicationTests {
    companion object {
        private val mongodbContainer = MongoDBContainer("mongo:4.4").apply {
            this.start()
        }

        @JvmStatic
        @DynamicPropertySource
        fun registerProperties(registry: DynamicPropertyRegistry) {
            registry.add("spring.data.mongodb.uri", mongodbContainer::getReplicaSetUrl)
        }
    }

    @Test
    fun contextLoads() {
    }

    @Autowired
    lateinit var contentService: ContentService

    @Autowired
    lateinit var contentRepository: ContentRepository

    @Test
    fun `createContent - Content 저장`() {
        // when
        contentService.createContent(
            type = ContentType.NOVEL,
            title = "Novel 1",
            description = "This is a novel content"
        )

        // then
        val contents = contentRepository.findAll()

        assertThat(contents).hasSize(1)
        assertThat(contents[0].type).isEqualTo(ContentType.NOVEL)
        assertThat(contents[0].information.title).isEqualTo("Novel 1")
        assertThat(contents[0].information.description).isEqualTo("This is a novel content")
    }

    @Test
    fun `createContent - Content 저장 후 Exception 발생 시 저장되지 않는다`() {
        // when
        assertThatThrownBy {
            contentService.createContent(
                type = ContentType.NOVEL,
                title = "Novel 1",
                description = "This is a novel content",
                throws = true
            )
        }.isInstanceOf(RuntimeException::class.java)

        // then
        val contents = contentRepository.findAll()

        assertThat(contents).hasSize(0)
    }

    @AfterEach
    fun tearDown() {
        contentRepository.deleteAll()
    }
}

 

각 테스트에 대해 설명하면

 

- createContent - Content 저장

정상적인 상황에서 Content entity 저장이 잘 되었는지를 확인하기 위한 테스트이다.

저장이 잘 되었기 때문에 ContentRepository를 통해 조회가 가능하다.

 

테스트 실행 후 로그를 확인하면 다음과 같이 commit이 된 것을 확인할 수 있다.

 

- createContent - Content 저장 후 Exception 발생 시 저장되지 않는다

Content 저장 이후 Exception을 발생시켰을 때 Transaction 처리가 잘 되었는지를 확인한다.

Exception이 발생하여 Rollback이 되면 저장된 Content가 없어야 할 것 이다.

 

테스트 실행 후 로그를 확인하면 다음과 같이 rollback이 된 것을 확인할 수 있다.

 


 

이사응로 Spring Data MongoDB를 사용하여 Application을 만들고 이를 테스트하는 방법에 대해 알아보는 것을 마치도록 하겠다.

댓글