如何在 SpringBoot v2.6.2 中使用嵌入式 MongoDB?

Lob*_*obo 8 java mongodb spring-boot junit5

我正在使用 Spring Boot v2.6.2 和 Java v17 并尝试在不运行 MongoDBService 的情况下测试我的 MongoConnection,因为它应该在构建机器上使用嵌入式内存 MongoDB 进行测试,无需在那里设置额外的 MongoDB 服务。当然,在生产系统上,它应该使用完整的 MongoDB。

我尝试运行这个简单的示例:

@DataMongoTest
public class MongoTest
{
    @Autowired
    private UserRepository userRepository;

    @AfterEach
    void cleanUpDatabase()
    {
        this.userRepository.deleteAll();
    }

    @Test
    void bootstrapTestDataWithMongoTemplate() {
        final var restaurant = new User( "123", "ABC", "DEF" );
        this.userRepository.insert( restaurant );

        final var found = this.userRepository.findByFirstName( "ABC" );

        System.out.println( found );
    }
}
Run Code Online (Sandbox Code Playgroud)

UserRepository是一个扩展的接口MongoRepositoryUser本身只是一个DBEntity带有@Document注释的。如果我让 SpringBoot 应用程序运行,而不是在测试模式下运行,则一切正常,因为 MongoDB 正在指定位置运行。但为了测试,我想让它作为内存数据库运行。

但Springboot想要连接进行测试。

@DataMongoTest
public class MongoTest
{
    @Autowired
    private UserRepository userRepository;

    @AfterEach
    void cleanUpDatabase()
    {
        this.userRepository.deleteAll();
    }

    @Test
    void bootstrapTestDataWithMongoTemplate() {
        final var restaurant = new User( "123", "ABC", "DEF" );
        this.userRepository.insert( restaurant );

        final var found = this.userRepository.findByFirstName( "ABC" );

        System.out.println( found );
    }
}
Run Code Online (Sandbox Code Playgroud)

关于如何执行此操作有什么建议吗?测试@DataMongoTest方法是否错误?我认为集成的 fladoodle 依赖项会自动将其注入到测试用例中。

pom 本身也没有那么复杂:

    2022-01-20 08:31:57.489  INFO 3976 --- [           main] org.mongodb.driver.cluster               : Cluster created with settings {hosts=[localhost:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms'}
2022-01-20 08:31:57.521  INFO 3976 --- [localhost:27017] org.mongodb.driver.cluster               : Exception in monitor thread while connecting to server localhost:27017

com.mongodb.MongoSocketOpenException: Exception opening socket
    at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:70) ~[mongodb-driver-core-4.4.0.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:180) ~[mongodb-driver-core-4.4.0.jar:na]
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:188) ~[mongodb-driver-core-4.4.0.jar:na]
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:152) ~[mongodb-driver-core-4.4.0.jar:na]
    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
Caused by: java.net.ConnectException: Connection refused: no further information
    at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na]
    at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:542) ~[na:na]
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:597) ~[na:na]
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na]
    at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]
    at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:107) ~[mongodb-driver-core-4.4.0.jar:na]
    at com.mongodb.internal.connection.SocketStream.initializeSocket(SocketStream.java:79) ~[mongodb-driver-core-4.4.0.jar:na]
    at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:65) ~[mongodb-driver-core-4.4.0.jar:na]
    ... 4 common frames omitted
Run Code Online (Sandbox Code Playgroud)

Sus*_*afa 22

文档指出:

\n
\n

2.2.4. 嵌入式蒙古

\n

Spring Boot 为嵌入式 Mongo 提供自动配置。要在\n您的 Spring Boot 应用程序中使用它,请添加对\nde.flapdoodle.embed:de.flapdoodle.embed.mongo 的依赖项,并设置\n spring.mongodb.embedded.version 属性以匹配\n您的 MongoDB 版本应用程序将在生产中使用。默认\n下载配置允许访问\n嵌入式 Mongo\xe2\x80\x99s 版本类中列出的大多数版本以及其他一些版本。配置可访问的版本将导致\n尝试下载服务器时出错。可以通过定义适当配置的 DownloadConfigBuilderCustomizer bean 来纠正此类错误。

\n

Mongo 监听的端口可以通过设置 spring.data.mongodb.port 属性来配置。要使用随机分配的空闲端口,请使用值 0。由 MongoAutoConfiguration 创建的 MongoClient 自动配置为使用随机分配的端口。如果您不配置自定义端口,则嵌入式支持默认使用随机端口(而不是 27017)。

\n

如果类路径上有 SLF4J,Mongo 生成的输出会自动路由到名为 norg.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongo 的记录器。

\n

您可以声明自己的 IMongodConfig 和 IRuntimeConfig beans 来控制 Mongo 实例\xe2\x80\x99s 配置和日志记录\n路由。可以通过声明\nDownloadConfigBuilderCustomizer bean 来自定义下载配置。

\n
\n

因此,如果您希望它仅应用于测试,请在scope:test中添加以下依赖项。

\n
    <dependency>\n        <groupId>de.flapdoodle.embed</groupId>\n        <artifactId>de.flapdoodle.embed.mongo</artifactId>\n        <scope>test</scope>\n    </dependency>\n
Run Code Online (Sandbox Code Playgroud)\n

您还需要在 application.properties 文件中设置版本:

\n
spring.mongodb.embedded.version=4.0.21\n
Run Code Online (Sandbox Code Playgroud)\n

https://docs.spring.io/spring-boot/docs/current/reference/html/data.html#data.nosql.mongodb.embedded

\n
\n

工作示例:

\n
<?xml version="1.0" encoding="UTF-8"?>\n<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.6.2</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.example.mongodb.embedded</groupId>\n    <artifactId>mongodb-app</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>mongodb-app</name>\n    <description>Demo project for usage of embedded mongodb</description>\n    <properties>\n        <java.version>11</java.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-mongodb</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.16</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>de.flapdoodle.embed</groupId>\n            <artifactId>de.flapdoodle.embed.mongo</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>integration-test</id>\n                        <goals>\n                            <goal>test</goal>\n                        </goals>\n                        <phase>integration-test</phase>\n                        <configuration>\n                            <excludes>\n                                <exclude>none</exclude>\n                            </excludes>\n                            <includes>\n                                <include>**/*IT.java</include>\n                            </includes>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n
Run Code Online (Sandbox Code Playgroud)\n

用户存储库:

\n
public interface UserRepository extends MongoRepository<User, Long> {\n\n    //Spring converts this to Regex findByFirstnameRegex(String firstname)  {"firstname" : {"$regex" : firstname }}\n    // automatically\n    public List<User> findByFirstName(String firstName);\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

用户:

\n
@Data\n@Builder\npublic class User {\n\n    @Id\n    private Long id;\n\n    private String firstName;\n    private String lastName;\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

测试:

\n
@DataMongoTest\n@TestInstance(TestInstance.Lifecycle.PER_CLASS)\npublic class UserControllerIT {\n\n    @Autowired\n    private UserRepository userRepository;\n\n    @BeforeAll\n    public void setup(){\n\n        userRepository.save(User.builder().id(1L).firstName("James").lastName("Bond").build());\n        userRepository.save(User.builder().id(2L).firstName("James").lastName("Farley").build());\n        userRepository.save(User.builder().id(3L).firstName("Marley").lastName("Hemp").build());\n        userRepository.save(User.builder().id(4L).firstName("James").lastName("Bond").build());\n\n    }\n\n    @Test\n    public void test_getById_successfull() throws Exception {\n        Assertions.assertEquals("James", userRepository.findByFirstName("James").get(0).getFirstName());\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

src/test/resources/application.properties

\n
spring.data.mongodb.database=test\nspring.data.mongodb.port=27017\nspring.mongodb.embedded.version=4.0.2\n
Run Code Online (Sandbox Code Playgroud)\n