Spring Boot Integration Testing with Embedded MongoDB – 嵌入MongoDB的Spring Boot集成测试

最后修改: 2018年 7月 7日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll learn how to use Flapdoodle’s embedded MongoDB solution together with Spring Boot to run MongoDB integration tests smoothly.

在本教程中,我们将学习如何将Flapdoodle的嵌入式MongoDB解决方案与Spring Boot一起使用,以顺利地运行MongoDB集成测试。

MongoDB is a popular NoSQL document database. Thanks to the high scalability, built-in sharding and excellent community support it’s often considered “the NoSQL storage” by many developers.

MongoDB是一个流行的NoSQL文档数据库。由于其高可扩展性、内置分片和出色的社区支持,它通常被许多开发人员认为是”theNoSQL存储”。

As with any other persistence technology, it’s critical to be able to test database integration with the rest of our application easily. Thankfully, Spring Boot allows us to write that kind of tests easily.

与其他持久性技术一样,能够轻松测试数据库与我们应用程序的其他部分的集成是至关重要的。值得庆幸的是,Spring Boot允许我们轻松编写这种测试。

2. Maven Dependencies

2.Maven的依赖性

First, let’s set up the Maven parent for our Boot project.

首先,让我们为我们的Boot项目设置Maven父体。

Thanks to the parent we don’t need to define version for each Maven dependency manually.

多亏了父辈我们不需要为每个Maven依赖对象手动定义版本

We’re naturally going to be using Spring Boot:

我们自然要使用Spring Boot。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

You can find the latest Boot version here.

你可以在这里找到最新的Boot版本

Since we added Spring Boot parent, we can add required dependencies without specifying their versions:

由于我们添加了Spring Boot父体,我们可以添加所需的依赖,而不需要指定它们的版本。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

spring-boot-starter-data-mongodb will enable Spring support for MongoDB:

spring-boot-starter-data-mongodb将启用Spring对MongoDB的支持。

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

de.flapdoodle.embed.mongo provides embedded MongoDB for integration tests.

de.flapdoodle.embed.mongo为集成测试提供嵌入式MongoDB。

3. Test Using Embedded MongoDB

3.使用嵌入式MongoDB进行测试

This section covers two scenarios: Spring Boot test and manual test.

本节涵盖两种情况。Spring Boot测试和手动测试。

3.1. Spring Boot Test

3.1.Spring Boot测试

After adding de.flapdoodle.embed.mongo dependency Spring Boot will automatically try to download and start the embedded MongoDB when running tests.

添加de.flapdoodle.embed.mongo依赖后Spring Boot在运行测试时将自动尝试下载并启动嵌入式MongoDB

The package will be downloaded only once for each version so that subsequent tests run much faster.

每个版本的软件包只需下载一次,这样后续的测试就会运行得更快。

At this stage we should be able to start and pass the sample JUnit 5 integration test:

在这个阶段,我们应该能够启动并通过JUnit 5集成测试样本。

@DataMongoTest
@ExtendWith(SpringExtension.class)
public class MongoDbSpringIntegrationTest {
    @DisplayName("given object to save"
        + " when save object using MongoDB template"
        + " then object is saved")
    @Test
    public void test(@Autowired MongoTemplate mongoTemplate) {
        // given
        DBObject objectToSave = BasicDBObjectBuilder.start()
            .add("key", "value")
            .get();

        // when
        mongoTemplate.save(objectToSave, "collection");

        // then
        assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
            .containsOnly("value");
    }
}

As we can see, the embedded database was automatically started by Spring, which should also be logged in the console:

我们可以看到,嵌入式数据库被Spring自动启动,这也应该被记录在控制台中。

...Starting MongodbExampleApplicationTests on arroyo with PID 10413...

3.2. Manual Configuration Test

3.2.手动配置测试

Spring Boot will automatically start and configure the embedded database and then inject MongoTemplate instance for us. However, sometimes we might need to configure embedded Mongo database manually (e.g., when testing a specific DB version).

Spring Boot会自动启动和配置嵌入式数据库,然后为我们注入MongoTemplate实例。然而,有时我们可能需要手动配置嵌入式Mongo数据库(例如,在测试特定DB版本时)。

The following snippet shows how we can configure the embedded MongoDB instance manually. This is roughly the equivalent of the previous Spring test:

下面的片段展示了我们如何手动配置嵌入式MongoDB实例。这大致相当于之前的Spring测试。

class ManualEmbeddedMongoDbIntegrationTest {
    private static final String CONNECTION_STRING = "mongodb://%s:%d";

    private MongodExecutable mongodExecutable;
    private MongoTemplate mongoTemplate;

    @AfterEach
    void clean() {
        mongodExecutable.stop();
    }

    @BeforeEach
    void setup() throws Exception {
        String ip = "localhost";
        int port = 27017;

        ImmutableMongodConfig mongodConfig = MongodConfig
            .builder()
            .version(Version.Main.PRODUCTION)
            .net(new Net(ip, port, Network.localhostIsIPv6()))
            .build();

        MongodStarter starter = MongodStarter.getDefaultInstance();
        mongodExecutable = starter.prepare(mongodConfig);
        mongodExecutable.start();
        mongoTemplate = new MongoTemplate(MongoClients.create(String.format(CONNECTION_STRING, ip, port)), "test");
    }

    @DisplayName("given object to save"
        + " when save object using MongoDB template"
        + " then object is saved")
    @Test
    void test() throws Exception {
        // given
        DBObject objectToSave = BasicDBObjectBuilder.start()
            .add("key", "value")
            .get();

        // when
        mongoTemplate.save(objectToSave, "collection");

        // then
        assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
            .containsOnly("value");
    }
}

Note, that we can quickly create MongoTemplate bean configured to use our manually configured embedded database and register it inside the Spring container by merely creating, e.g., a @TestConfiguration with @Bean method that will return new MongoTemplate(MongoClients.create(connectionString, “test”).

请注意,我们可以快速创建MongoTemplate Bean,将其配置为使用我们手动配置的嵌入式数据库,并在Spring容器中注册,只需创建@TestConfiguration,并使用@Bean方法返回new MongoTemplate(MongoClients.create(connectionString, “test”)/em>。

More examples can be found on the official Flapdoodle’s GitHub repository.

更多的例子可以在Flapdoodle官方的GitHub资源库中找到。

3.3. Logging

3.3.伐木

We can configure logging messages for MongoDB when running integration tests by adding these two properties to src/test/resources/application.propertes file:

我们可以通过在src/test/resources/application.propertes文件中添加这两个属性来配置运行集成测试时MongoDB的日志信息。

logging.level.org.springframework.boot.autoconfigure.mongo.embedded
logging.level.org.mongodb

For example, to disable logging, we simply set the values to off:

例如,要禁用日志记录,我们只需将这些值设置为off

logging.level.org.springframework.boot.autoconfigure.mongo.embedded=off
logging.level.org.mongodb=off

3.4. Using a Real Database on Production

3.4.在生产中使用真实的数据库

Since we added de.flapdoodle.embed.mongo dependency using <scope>test</scope> there’s no need to disable embedded database when running on production. All we have to do is to specify MongoDB connection details (e.g., host and port) and we are good to go.

由于我们使用de.flapdoodle.embed.mongo添加了<scope>test</scope>在生产环境中运行时,没有必要禁用嵌入式数据库。我们所要做的就是指定MongoDB的连接细节(例如,主机和端口),我们就可以开始了。

To use an embedded DB outside of tests, we can use Spring profiles that will register the right MongoClient (embedded or production) depending on the active profile.

为了在测试之外使用嵌入式数据库,我们可以使用Spring配置文件,它将根据活动配置文件注册正确的MongoClient(嵌入式或生产型)。

We’ll also need to change the scope of the production dependency to <scope>runtime</scope>.

我们还需要将生产依赖的范围改为<范围>运行时</scope>

4. Embedded Testing Controversy

4.嵌入式测试的争论

Using embedded database might look like a great idea at the beginning. Indeed, it’s a good approach when we want to test if our application behaves correctly in areas such as:

使用嵌入式数据库在开始时可能看起来是个好主意。的确,当我们想测试我们的应用程序在以下方面的行为是否正确时,这是一个好方法。

  • Object<->Document mapping configuration
  • Custom persistence lifecycle event listeners (refer to AbstractMongoEventListener)
  • The logic of any code working directly with the persistence layer

Unfortunately, using an embedded server cannot be considered as “full integration testing”. Flapdoodle’s embedded MongoDB isn’t an official MongoDB product. Therefore, we cannot be sure that it behaves exactly as in the production environment.

不幸的是,使用嵌入式服务器不能被视为 “完全集成测试”。Flapdoodle的嵌入式MongoDB并不是一个官方的MongoDB产品。因此,我们不能确定它的行为是否与生产环境中的行为完全一致。

If we want to run communication tests in the environment as close to the production as possible, a better solution is to use an environment container such as Docker.

如果我们想在尽可能接近生产的环境中运行通信测试,一个更好的解决方案是使用环境容器,如Docker。

To find out more about Docker, read our previous article here.

要了解有关Docker的更多信息,请阅读我们之前的文章这里

5. Conclusion

5.结论

Spring Boot makes it extremely simple to run tests that verify proper document mapping and database integration. By adding the right Maven dependency, we are immediately able to use MongoDB components in Spring Boot integration tests.

Spring Boot使运行验证正确的文档映射和数据库集成的测试变得极为简单。通过添加正确的Maven依赖性,我们马上就能在Spring Boot集成测试中使用MongoDB组件。

We need to remember that embedded MongoDB server cannot be considered a replacement for a “real” server.

我们需要记住,嵌入式MongoDB服务器不能被认为是 “真正 “服务器的替代品

The full source code of all the examples is available over on GitHub.

所有例子的完整源代码都可以在GitHub上找到