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