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 (채택)
- java 로 가짜 mongoDB 서버를 구현하는 오픈소스 라이브러리입니다.
- https://github.com/bwaldvogel/mongo-java-server#fuzzy-backend
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);
}
}
간단하게 끝!
- 코드 : github
- spring mongodb 설정 : blog posting
참고