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

问题描述 投票:0回答:2

我正在使用 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 );
    }
}

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

但是Springboot想要连接进行测试。

    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

关于如何做到这一点有什么建议吗?

@DataMongoTest
测试方式是否错误?我认为集成的 fladoodle 依赖项会自动将其注入到测试用例中。

pom 本身也没有那么复杂:

<properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.openjson</groupId>
            <artifactId>openjson</artifactId>
            <version>1.0.11</version>
        </dependency>
        <dependency>
            <groupId>com.github.erosb</groupId>
            <artifactId>everit-json-schema</artifactId>
            <version>1.14.0</version>
        </dependency>
    </dependencies>
java mongodb spring-boot junit5
2个回答
20
投票

文档指出:

2.2.4。嵌入式 Mongo

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

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

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

您可以声明自己的 IMongodConfig 和 IRuntimeConfig bean 控制 Mongo 实例的配置和日志记录 路由。下载配置可以通过声明来定制 下载ConfigBuilderCustomizer bean。

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

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

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

spring.mongodb.embedded.version=4.0.21

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


工作示例:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.mongodb.embedded</groupId>
    <artifactId>mongodb-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mongodb-app</name>
    <description>Demo project for usage of embedded mongodb</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <phase>integration-test</phase>
                        <configuration>
                            <excludes>
                                <exclude>none</exclude>
                            </excludes>
                            <includes>
                                <include>**/*IT.java</include>
                            </includes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

用户存储库:

public interface UserRepository extends MongoRepository<User, Long> {

    //Spring converts this to Regex findByFirstnameRegex(String firstname)  {"firstname" : {"$regex" : firstname }}
    // automatically
    public List<User> findByFirstName(String firstName);

}

用户:

@Data
@Builder
public class User {

    @Id
    private Long id;

    private String firstName;
    private String lastName;

}

测试:

@DataMongoTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserControllerIT {

    @Autowired
    private UserRepository userRepository;

    @BeforeAll
    public void setup(){

        userRepository.save(User.builder().id(1L).firstName("James").lastName("Bond").build());
        userRepository.save(User.builder().id(2L).firstName("James").lastName("Farley").build());
        userRepository.save(User.builder().id(3L).firstName("Marley").lastName("Hemp").build());
        userRepository.save(User.builder().id(4L).firstName("James").lastName("Bond").build());

    }

    @Test
    public void test_getById_successfull() throws Exception {
        Assertions.assertEquals("James", userRepository.findByFirstName("James").get(0).getFirstName());
    }

}

src/test/resources/application.properties

spring.data.mongodb.database=test
spring.data.mongodb.port=27017
spring.mongodb.embedded.version=4.0.2

0
投票

对于未来在尝试让嵌入式 mongo 工作时偶然发现这一点的任何人 - Spring 显然从 v2.7.0 开始删除了内置支持,因此原始的 flappodle 模块不再适用于较新版本的 Spring。值得庆幸的是,fladdoodle 有您可以导入的“姐妹”模块,它们应该提供相同的功能,尽管配置略有不同。它们可以通过原始模块的文档找到。

© www.soinside.com 2019 - 2024. All rights reserved.