ChatGPT解决这个技术问题 Extra ChatGPT

运行集成测试时嵌入 MongoDB

我的问题是 this one 的变体。

由于我的 Java Web 应用程序项目需要大量读取过滤器/查询以及与 GridFS 等工具的接口,因此我正在努力想出一种以上述解决方案建议的方式使用 MongoDB 的明智方法。

因此,我正在考虑在集成测试的同时运行 MongoDB 的嵌入式实例。我希望它自动启动(对于每个测试或整个套件),为每个测试刷新数据库,并在最后关闭。这些测试可能在开发机器和 CI 服务器上运行,所以我的解决方案也需要是可移植的。

任何对 MongoDB 有更多了解的人都可以帮助我了解这种方法的可行性,和/或建议任何可能帮助我入门的阅读材料吗?

我也愿意接受人们可能对我如何解决这个问题提出的其他建议......

如果您使用的是 maven,则可以使用我们的 mvnrepository.com/artifact/com.wenzani/mongodb-maven-plugin
您还可以检查这个项目,它在 JVM 内存中模拟 MongoDB。 github.com/thiloplanz/jmockmongo 但它仍在开发中。
不只是为了单元测试,如果你想在 Linux 上运行 MongoDB(甚至是集群)作为内存部署,请阅读这篇博文。 edgystuff.tumblr.com/post/49304254688 不过,如果能像 RavenDB 那样开箱即用,那就太好了。
与此处提到的 embedmongo-maven-plugin 类似,还有一个 Gradle Mongo Plugin 可用。与 Maven 插件一样,它也包装了 flapdoodle EmbeddedMongoDb api 并允许您从 Gradle 构建中运行 Mongo 的托管实例。
在此处查看此代码示例:github.com/familysyan/embedded-mongo-integ。无需安装,无需依赖。它只是一个独立于平台的 ant 脚本,可以为您下载和设置。它还会在您的测试后清理所有内容。

M
Matt Clark

我发现 Embedded MongoDB 库看起来很有前途并且可以满足您的要求。

当前支持 MongoDB 版本:1.6.53.1.6,前提是二进制文件仍可从配置的镜像中获得。

这是一个简短的使用示例,我刚刚尝试过并且效果很好:

public class EmbeddedMongoTest {
    private static final String DATABASE_NAME = "embedded";

    private MongodExecutable mongodExe;
    private MongodProcess mongod;
    private Mongo mongo;

    @Before
    public void beforeEach() throws Exception {
        MongoDBRuntime runtime = MongoDBRuntime.getDefaultInstance();
        mongodExe = runtime.prepare(new MongodConfig(Version.V2_3_0, 12345, Network.localhostIsIPv6()));
        mongod = mongodExe.start();
        mongo = new Mongo("localhost", 12345);
    }

    @After
    public void afterEach() throws Exception {
        if (this.mongod != null) {
            this.mongod.stop();
            this.mongodExe.stop();
        }
    }

    @Test
    public void shouldCreateNewObjectInEmbeddedMongoDb() {
        // given
        DB db = mongo.getDB(DATABASE_NAME);
        DBCollection col = db.createCollection("testCollection", new BasicDBObject());

        // when
        col.save(new BasicDBObject("testDoc", new Date()));

        // then
        assertThat(col.getCount(), Matchers.is(1L));
    }
}

刚刚使用了这个库,它在 Mac 上完美地运行了 JUnit 测试 Mongo API。推荐的。
+1 很棒的发现!一年前我第一次开始使用 mongodb 时,没有针对数据库进行测试的编程方式是缺点之一。我们通过在每个环境中都有一个测试实例来解决这个问题,通过 Java 属性文件进行配置,但当然需要在每个环境中安装 mongo。这看起来会解决所有这些问题。
好的!删除了我的答案,因为它不再准确。有人知道这有多成熟吗?我可以想象它必须在非常低的级别上模拟 MongoDB 会非常复杂,并且从源代码来看它看起来非常高级。
终于在我的项目中使用了这个,并且可以报告它非常容易设置和运行。低级调用都是官方 com.mongodb Java API 的一部分,因此它并不比使用常规 API 复杂。
小心这个解决方案。它只是收集有关当前操作系统的信息并从 Internet 下载适当的特定于平台的 MongoDB 二进制文件,运行守护程序并执行一些其他配置工作。作为企业解决方案,事实并非如此。嘲笑可能是唯一真正的选择。
C
Collin Krawll

这是 accepted answer from @rozky 的更新(2022 年)版本(在 Mongo 和 Embedded MongoDB 库中进行了很多更改)。

package com.example.mongo;

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
import java.util.Date;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class EmbeddedMongoTest {

    private static final String DATABASE_NAME = "embedded";

    private MongodExecutable mongodExe;
    private MongodProcess mongod;
    private MongoClient mongo;

    @Before
    public void beforeEach() throws Exception {
        MongodStarter starter = MongodStarter.getDefaultInstance();
        String bindIp = "localhost";
        int port = 12345;
        MongodConfig mongodConfig = MongodConfig.builder()
            .version(Version.Main.PRODUCTION)
            .net(new Net(bindIp, port, Network.localhostIsIPv6()))
            .build();
        this.mongodExe = starter.prepare(mongodConfig);
        this.mongod = mongodExe.start();
        this.mongo = new MongoClient(bindIp, port);
    }

    @After
    public void afterEach() throws Exception {
        if (this.mongod != null) {
            this.mongod.stop();
            this.mongodExe.stop();
        }
    }

    @Test
    public void shouldCreateNewObjectInEmbeddedMongoDb() {
        // given
        MongoDatabase db = mongo.getDatabase(DATABASE_NAME);
        db.createCollection("testCollection");
        MongoCollection<BasicDBObject> col = db.getCollection("testCollection", BasicDBObject.class);

        // when
        col.insertOne(new BasicDBObject("testDoc", new Date()));

        // then
        assertEquals(1L, col.countDocuments());
    }

}

为每个测试重复启动和停止 Embedded mongo 会导致大多数测试失败。最好在所有测试之前启动并在所有测试都执行后关闭
您需要在上面的更改中包含 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@DBS您也可以使用随机端口,以便您仍然可以在新的嵌入式mongo实例上同时运行测试。请参阅文档 here
是的,这就像一个魅力。从 baeldung 来到这里 - 这个例子一直在抛出 原因:java.lang.IllegalArgumentException:数据库名称不能为空!虽然我确实在 (MongoClients.create(String.format(CONNECTION_STRING, ip, port)), "cipresale");
@sashikanta 我刚刚更新了最新更改的代码(具体来说,我将 IMongodConfig mongodConfig = new MongodConfigBuilder() 更改为 MongodConfig mongodConfig = MongodConfig.builder())。请现在再试一次。
z
zlob

有 Foursquare 产品 Fongo。 Fongo 是 mongo 的内存中 java 实现。它拦截对标准 mongo-java-driver 的调用,用于查找、更新、插入、删除和其他方法。主要用途是用于轻量级单元测试,您不想启动 mongo 进程。


Fongo 是否会拦截对网络的调用,例如对 localhost:27017 的调用,以便它可以充当插入式假服务器以启用集成测试而无需更改代码?
mongo-java-server 是一种插入式假服务器实现,无需更改代码即可用于集成测试。
j
joelittlejohn

如果您使用的是 Maven,您可能会对我创建的包含 flapdoodle.de 'embedded mongo' API 的插件感兴趣:

嵌入mongo-maven-插件

它提供了一个 start 目标,您可以使用它来启动您想要的任何 MongoDB 版本(例如在 pre-integration-test 期间),以及一个将停止 MongoDB 的 stop 目标(例如在 post-integration-test 期间)。

与其他插件相比,使用此插件的真正好处是不需要事先安装 MongoDB。下载 MongoDB 二进制文件并将其存储在 ~/.embedmongo 中以供将来构建。


这是 Leiningen 的 Clojure 版本:github.com/joelittlejohn/lein-embongo
A
Aurélien Thieriot

如果您使用的是 sbt 和 specs2,我为 embedmongo 编写了相同类型的包装器

https://github.com/athieriot/specs2-embedmongo


p
panser

使用 spring-boot 1.3 你可以使用 EmbeddedMongoAutoConfiguration

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{
}

你能解释一下“@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })”注释实际上在做什么吗?
原因很可能是 de.flapdoodle.embed.mongo 依赖项未标记为测试范围。不要在生产应用程序设置中选择并运行嵌入式 mongo,需要排除。
I
Irwin

从版本 3.2.6 开始,您可以在内存中运行 MongoDB。从 site

从 MongoDB Enterprise 版本 3.2.6 开始,内存存储引擎是 64 位版本中通用可用性 (GA) 的一部分。除了一些元数据和诊断数据,内存存储引擎不维护任何磁盘数据,包括配置数据、索引、用户凭据等。


D
Dheeraj kumar

不仅用于单元测试,还解释了如何将 inmemory mongodb 与 rest api 一起使用。

maven依赖:

        <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>
        </dependency>

==================================================== ============================

应用程序属性

server.port = 8080
spring.data.mongodb.database=user_db
spring.data.mongodb.port=27017
spring.data.mongodb.host=localhost

==================================================== ============================

用户存储库.java

公共接口 UserRepository 扩展 MongoRepository{

}

供参考和所有java代码使用下面的链接:(一步一步的解释)

https://www.youtube.com/watch?v=2Tq2Q7EzhSA&t=7s


b
bubbles

使用 storageEngine='ephemeralForTest' 执行 mongod 时性能更好

new MongodConfigBuilder()
    .version(Version.Main.PRODUCTION)
    .cmdOptions(new MongoCmdOptionsBuilder()
         .useStorageEngine("ephemeralForTest")
         .build())
    .net(new Net("localhost", port, Network.localhostIsIPv6()))
    .build()

P
Punit Tiwari

要运行嵌入式 mongodb 进行集成测试,需要以下 maven 依赖项:

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.5.2</version>
        </dependency>

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

尝试使用为 EmbeddedMongoAutoConfiguration 截取的以下代码:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class EmbeddedMongoApplication {

    public static void main(String[] args) {
         System.setProperty("os.arch", "x86_64");
         SpringApplication.run(EmbeddedMongoApplication.class, args);
    }
    
    @Bean
    public EmbeddedMongoAutoConfiguration embeddedMongoAutoConfiguration(MongoProperties mongoProperties) {
        return new EmbeddedMongoAutoConfiguration(mongoProperties);
    }
}

笔记:

嵌入式 mongodb 将下载到以下路径。因此,请考虑该路径具有适当的权限。

Linux : $HOME/.embedmongo/linux/mongodb-linux-x86_64-3.2.2.tgz
Windows : C:\Users\<username>\.embedmongo\win32\mongodb-win32-x86_64-3.x.x.zip

J
Jackson

在生产中,您将使用真实的数据库。

如果您希望您的测试反映您的产品在生产中的行为方式,请使用 Mongo 的真实实例。

伪造的实现可能与真实的实现不完全相同。在测试时,您应该争取正确性。执行速度排在第二位。


我想你错过了我的目的。我不是在寻找一个假的 Mongo 实例,我想要一个真实的实例,但嵌入到我的测试中。原因是启动 MongoDB 并将其置于特定状态而不会污染现有数据库,运行一系列操作,然后检查结果,而无需筛选与我的测试无关的任意数据。在保持受控测试环境的同时尽可能真实。
抱歉,“模拟”这个词和所有这些“内存中”的建议让我忘记了 Java 领域中“嵌入”的含义。很高兴听到。