如何在Spring Boot应用程序中配置嵌入式MongDB进行集成测试?

我有一个相当简单的Spring Boot应用程序,它公开一个小的REST API并从MongoDB的一个实例中检索数据。 对MongoDB实例的查询通过基于Spring Data的存储库进行。 下面的一些关键代码。

// Main application class @EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) @ComponentScan @Import(MongoConfig.class) public class ProductApplication { public static void main(String[] args) { SpringApplication.run(ProductApplication.class, args); } } 
 // Product repository with Spring data public interface ProductRepository extends MongoRepository { Page findAll(Pageable pageable); Optional findByLineNumber(String lineNumber); } 
 // Configuration for "live" connections @Configuration public class MongoConfig { @Value("${product.mongo.host}") private String mongoHost; @Value("${product.mongo.port}") private String mongoPort; @Value("${product.mongo.database}") private String mongoDatabase; @Bean(name="mongoClient") public MongoClient mongoClient() throws IOException { return new MongoClient(mongoHost, Integer.parseInt(mongoPort)); } @Autowired @Bean(name="mongoDbFactory") public MongoDbFactory mongoDbFactory(MongoClient mongoClient) { return new SimpleMongoDbFactory(mongoClient, mongoDatabase); } @Autowired @Bean(name="mongoTemplate") public MongoTemplate mongoTemplate(MongoClient mongoClient) { return new MongoTemplate(mongoClient, mongoDatabase); } } 
 @Configuration @EnableMongoRepositories public class EmbeddedMongoConfig { private static final String DB_NAME = "integrationTest"; private static final int DB_PORT = 12345; private static final String DB_HOST = "localhost"; private static final String DB_COLLECTION = "products"; private MongodExecutable mongodExecutable = null; @Bean(name="mongoClient") public MongoClient mongoClient() throws IOException { // Lots of calls here to de.flapdoodle.embed.mongo code base to // create an embedded db and insert some JSON data } @Autowired @Bean(name="mongoDbFactory") public MongoDbFactory mongoDbFactory(MongoClient mongoClient) { return new SimpleMongoDbFactory(mongoClient, DB_NAME); } @Autowired @Bean(name="mongoTemplate") public MongoTemplate mongoTemplate(MongoClient mongoClient) { return new MongoTemplate(mongoClient, DB_NAME); } @PreDestroy public void shutdownEmbeddedMongoDB() { if (this.mongodExecutable != null) { this.mongodExecutable.stop(); } } } 
 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = TestProductApplication.class) @IntegrationTest @WebAppConfiguration public class WtrProductApplicationTests { @Test public void contextLoads() { // Tests empty for now } } 
 @EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) @ComponentScan @Import(EmbeddedMongoConfig.class) public class TestProductApplication { public static void main(String[] args) { SpringApplication.run(TestProductApplication.class, args); } } 

所以这里的想法是让集成测试(此时为空)连接到嵌入式mongo实例而不是“实时”实例。 但是,它不起作用。 我可以看到测试连接到Mongo的“实时”实例,如果我关闭它,构建就会失败,因为它仍然试图连接到Mongo的实例。 有人知道为什么吗? 如何让测试连接到嵌入式实例?

这对我有用。

测试类:

  @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { Application.class, TestMongoConfig.class // <--- Don't forget THIS }) public class GameRepositoryTest { @Autowired private GameRepository gameRepository; @Test public void shouldCreateGame() { Game game = new Game(null, "Far Cry 3"); Game gameCreated = gameRepository.save(game); assertEquals(gameCreated.getGameId(), gameCreated.getGameId()); assertEquals(game.getName(), gameCreated.getName()); } } 

简单的MongoDB存储库:

 public interface GameRepository extends MongoRepository { Game findByName(String name); } 

MongoDB测试配置:

 import com.mongodb.Mongo; import com.mongodb.MongoClientOptions; import de.flapdoodle.embed.mongo.MongodExecutable; import de.flapdoodle.embed.mongo.MongodProcess; import de.flapdoodle.embed.mongo.MongodStarter; import de.flapdoodle.embed.mongo.config.IMongodConfig; import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; import de.flapdoodle.embed.mongo.config.Net; import de.flapdoodle.embed.mongo.distribution.Version; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; @Configuration public class TestMongoConfig { @Autowired private MongoProperties properties; @Autowired(required = false) private MongoClientOptions options; @Bean(destroyMethod = "close") public Mongo mongo(MongodProcess mongodProcess) throws IOException { Net net = mongodProcess.getConfig().net(); properties.setHost(net.getServerAddress().getHostName()); properties.setPort(net.getPort()); return properties.createMongoClient(this.options); } @Bean(destroyMethod = "stop") public MongodProcess mongodProcess(MongodExecutable mongodExecutable) throws IOException { return mongodExecutable.start(); } @Bean(destroyMethod = "stop") public MongodExecutable mongodExecutable(MongodStarter mongodStarter, IMongodConfig iMongodConfig) throws IOException { return mongodStarter.prepare(iMongodConfig); } @Bean public IMongodConfig mongodConfig() throws IOException { return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build(); } @Bean public MongodStarter mongodStarter() { return MongodStarter.getDefaultInstance(); } } 

的pom.xml

   org.springframework.boot spring-boot-starter-data-mongodb   de.flapdoodle.embed de.flapdoodle.embed.mongo 1.48.0 test  

从Spring Boot 1.3版开始,就有一个EmbeddedMongoAutoConfiguration类,它开箱即用。 这意味着您根本不必创建配置文件,并且如果您想要更改仍然可以的内容。

添加了嵌入式MongoDB的自动配置。 对de.flapdoodle.embed:de.flapdoodle.embed.mongo的依赖是开始所需的全部内容。 可以通过application.properties控制配置,例如要使用的Mongo版本。 有关详细信息,请参阅文档。 ( Spring Boot发行说明 )

必须添加到application.properties文件的最基本和最重要的配置是
spring.data.mongodb.port=0 (0表示将从免费中随机选择)

有关更多详细信息,请查看: Spring Boot Docs MongoDb

我将完成以前的答案

的pom.xml

  org.springframework.boot spring-boot-starter-parent 1.3.2.RELEASE  ...  org.springframework.boot spring-boot-starter-data-mongodb   de.flapdoodle.embed de.flapdoodle.embed.mongo ${embedded-mongo.version}  

MongoConfig

 @Configuration @EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class }) public class MongoConfig{ } 

在1.5.7版本中使用此:

 @RunWith(SpringRunner.class) @DataMongoTest public class UserRepositoryTests { @Autowired UserRepository repository; @Before public void setUp() { User user = new User(); user.setName("test"); repository.save(user); } @Test public void findByName() { List result = repository.findByName("test"); assertThat(result).hasSize(1).extracting("name").contains("test"); } } 

   de.flapdoodle.embed de.flapdoodle.embed.mongo  

确保你明确使用@ComponentScan 。 默认,

如果未定义特定包,则将使用此批注从类的包中进行扫描。 ( @ComponentScan Javadoc )

因此,如果您的TestProductApplicationProductApplication配置都在同一个包中,则Spring可能TestProductApplication您的ProductApplication配置进行组件扫描并使用它。

另外,我建议将Test mongo bean放入’test’或’local’配置文件中,并在测试类中使用@ActiveProfiles注释来启用测试/本地配置文件。