【问题标题】:How do you configure Embedded MongDB for integration testing in a Spring Boot application?如何配置 Embedded MongoDB 以在 Spring Boot 应用程序中进行集成测试?
【发布时间】:2015-10-12 15:16:38
【问题描述】:

我有一个相当简单的 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<Product, String> {

    Page<Product> findAll(Pageable pageable);

    Optional<Product> 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 的实时实例。有人知道为什么吗?如何让测试连接到嵌入式实例?

【问题讨论】:

  • 坦率地说,我整天都在修改注释和设置,但没有运气。修改 Spring Boot 应用程序以使其可测试似乎类似于拔牙......
  • 如今,只要存在 maven 依赖项 de.flapdoodle.embed:de.flapdoodle.embed.mongo,您很可能只需要 spring.data.mongodb.portspring.mongodb.embedded.*

标签: java spring mongodb spring-boot


【解决方案1】:

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

已添加嵌入式 MongoDB 的自动配置。对 de.flapdoodle.embed:de.flapdoodle.embed.mongo 的依赖是开始所必需的。可以通过 application.properties 控制配置,例如要使用的 Mongo 版本。请参阅文档以获取更多信息。 (Spring Boot Release Notes)

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

更多详情请查看:Spring Boot Docs MongoDb

【讨论】:

  • 谢谢。 spring.data.mongodb.port=0 很重要 - 没有它,当许多测试一起运行时,一些测试会随机失败。
  • 它仍然有效。在用于测试的嵌入式 Mongo 配置方面,Spring Boot 1.5 没有任何变化。只需确保添加与 mongo 驱动程序版本相对应的正确版本的fladdoodle.embed.mongo
  • 只是添加 'de.flapdoodle.embed.mongo' 依赖,这是行不通的。有人可以提供e代码示例吗?
  • 你的类路径上需要de.flapdoodle.embed.mongo com.mongodbgithub.com/spring-projects/spring-boot/blob/master/…
  • 找到它: spring.mongodb.embedded.version 。全文docs.spring.io/spring-boot/docs/current/reference/html/…
【解决方案2】:

编辑:请参阅 magiccrafter's answer 了解 Spring Boot 1.3+,使用 EmbeddedMongoAutoConfiguration

如果您因任何原因无法使用它,请继续阅读。


测试类:

    @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, String>     {

    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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <version>1.48.0</version>
            <scope>test</scope>
        </dependency>

【讨论】:

  • 原来我缺少的是后面的部分:@SpringApplicationConfiguration(classes = {Application.class, TestMongoConfig.class}) - 我没有意识到你也需要注释中的配置为了把它捡起来
  • 我遵循了您的实现,但是当我在 POM 中指定范围为测试时它对我不起作用,在构建应用程序时我收到错误“由:java.lang.ClassNotFoundException:de.flapdoodle .embed.mongo.distribution.IFeatureAwareVersion”,当我从 POM 中删除范围测试时,我收到以下错误“NoSuchBeanDefinitionException:没有定义名为 'embeddedMongoServer' 的 bean”
  • 我在创建名为 'testMongoConfig' 的 bean 时出错,没有合格的 bean 错误。
  • Repository 获取实际的集合配置,而不是从 TestMongoConfig 类获取配置。谁能帮我解决这个问题
【解决方案3】:

在 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<User> result = repository.findByName("test");
        assertThat(result).hasSize(1).extracting("name").contains("test");
    }

}

还有

        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
        </dependency>

【讨论】:

  • 如果你想测试一个可以访问嵌入式 mongo db 的控制器?
  • 您可以像使用真正的 MongoDB 一样注入 MongoClient 的实例,也可以注入 MongoTemplate
【解决方案4】:

我会完成上一个答案

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.2.RELEASE</version>
</parent>
 ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <version>${embedded-mongo.version}</version>
    </dependency>

MongoConfig

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

【讨论】:

  • 这是我需要在我的 Mongo 配置中让它停止杀死我的 Swagger2 测试(后续测试无法正确启动)以上项目让我思考,这最终是为了我。 Spring 4.x 版 Spring 自动配置 1.3.2 @EnableAutoConfiguration(exclude={EmbeddedMongoAutoConfiguration.class
【解决方案5】:

确保您的@ComponentScan 是明确的。默认情况下,

如果未定义特定包,扫描将从 带有此注解的类的包。 (@ComponentScan Javadoc)

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

此外,我建议将您的 Test mongo bean 放入“测试”或“本地”配置文件中,并在您的测试类中使用 @ActiveProfiles 注释来启用测试/本地配置文件。

【讨论】:

  • 活动配置文件注释可能是个好主意。我会继续的。
猜你喜欢
  • 2020-12-11
  • 1970-01-01
  • 2019-12-23
  • 1970-01-01
  • 2021-10-30
  • 2017-06-23
  • 2017-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多