Spring/Test-Driven Develop

[Spring] Embedded MongoDB! 통합테스트를 위한 인메모리 몽고디비 설정하기

민돌v 2023. 11. 6. 14:13
현재 mongodb와 mysql 을 함께 사용하고있는 프로젝트에서
통합테스트를 위해 mongodb 도 h2 같은 in-memory db로 사용할 수 있는게 없을까 찾아보다가 알게된 방법에 대해 정리하는 글 입니다.

 

공식적으로 Spring Document 에 언급된 in memory 방식의 nosql db 를 사용할 수 있는 방버을 찾지못해 오픈소스 라이브러리를 사용하였습니다. 참고해주세요!

 


 

✔️ Spring Boot 환경에서 Embedded MongoDB 를 사용하는 3가지 방법

 

1) de.flapdoodle.embed.mongo.spring

  • embeded mongodb 라고 검색하면 가장 많이 나오는 오픈소스 라이브러인 것 같습니다.
  • 나온지 10년 가까이된 것 같고, 지금까지도 활발하게 contribute 가 되어 관리되어지는 오픈소스 라이브러리로 보입니다.
  • https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo.spring

 

2) mongo-java-server (채택)

 

 

3) Docker TestContainers

  • 이런 경우에 있어서 테스트 컨테이너가 유용한 방법이 될거같지만, 러닝 커브도 있고 설정하는게 좀 귀찮아서 저는 패스했습니다
  • Java 코드로 Docker Container 를 구성할 수 있지 있지만, 당연하게도 개발환경에서 Docker 를 실행시켜야합니다.
  • 보통의 StackOverFlow 에서 가장 많이 추천하는 방식이라고 느껴졌습니다.

 

 

→ 저는 (2) 번 mongo-java-server 를 사용하였습니다.

1) 번을 처음 고려했으나, 가이드라인을 보았을 때 @ExtendWith(SpringExtension.class) @DirtyContext 를 사용하는게 좀 꺼림칙하기도 했고, 기존의 통합테스트 설정을 부분을 공통적으로 추상화 시켜놓았는데 @SpringBootTest 를 사용했기 때문에 패스했습니다.

 

(사실 테스트코드이기때문에,,, 제가 편한걸 선택했습니다 ㅎㅎ)

 


 

✔️ 격리된 통합테스트 환경에서 MongoDB 사용하기

aka. mongo-java-server 사용하기

> 기본적으로 오픈소스 가이드라인과 거의 유사합니다.

 

 

Config

  • fake mongo server 를 설정을 Bean 으로 올리고 어노테이션을 만들어줍니다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MongoTestServerConfig.class)
public @interface EnableMongoTestServer {

}
public class MongoTestServerConfig {

    @Bean
    public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory) {
        return new MongoTemplate(mongoDatabaseFactory);
    }

    @Bean
    public MongoDatabaseFactory mongoDatabaseFactory(MongoServer mongoServer) {
        String connection = mongoServer.getConnectionString();
        return new SimpleMongoClientDatabaseFactory(connection + "/test");
    }

    @Bean(destroyMethod = "shutdown")
    public MongoServer mongoServer() {
        MongoServer mongoServer = new MongoServer(new MemoryBackend());
        mongoServer.bind();
        return mongoServer;
    }
}

 

  • 그 다음 통합테스트에 사용할 공통적인 추상 클래스를 만들어줍니다.
  • 각 테스트 메소드끼리 영향을 주지 않기위해, 시작전 mongoDB 를 초기화 시켜주었습니다.
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@EnableMongoTestServer
@EnableMongoRepositories("com.mongoDB.repository")
public abstract class AcceptanceTestWithMongo {

    @Autowired
    MongoTemplate mongoTemplate;

    @BeforeEach
    public void setup() {

        mongoTemplate.getDb().drop();
    }
}

 


 

 

 

Test Code

class CRUDServiceTest extends AcceptanceTestWithMongo {

    @Autowired
    MessageService messageService;

    @Test
    public void run1() {

        messageService.create("홍길동", "니가가라 하와이");
        messageService.create("임창정", "내가 임마!");
        messageService.create("전창조", "1AM");

        List<Message> list = messageService.findAll();

        for (Message message : list) {
            System.out.println(message.toString());
        }

        Assertions.assertThat(list).hasSize(3);
    }

    @Test
    public void run2() {

        messageService.create("아델", "이츠미~");

        List<Message> list = messageService.findAll();

        for (Message message : list) {
            System.out.println(message.toString());
        }

        Assertions.assertThat(list).hasSize(1);

    }
}

 

 

 

간단하게 끝!

 

 

 

 

 


참고