运行集成测试时,嵌入式MongoDB


112

我的问题是这一个的变化

由于我的Java Web应用程序项目需要大量读取过滤器/查询以及与GridFS之类的工具的接口,因此,我很难以上述解决方案建议的方式来考虑采用MongoDB的明智方法。

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

任何对MongoDB有更多了解的人都可以帮助我了解这种方法的可行性,并且/或者可以提出任何可以帮助我入门的阅读材料吗?

我也乐于接受别人对我如何解决这个问题的建议...


如果您使用的是maven,则可以使用我们的mvnrepository.com/artifact/com.wenzani/mongodb-maven-plugin
markdsievers 2011年

您还可以检查此项目,该项目在JVM内存中模拟MongoDB。github.com/thiloplanz/jmockmongo但它仍在开发中。
Sebastien Lorber

不(仅适用于)单元测试,但是如果您想使用MongoDB(甚至集群)作为内存部署来运行(如果您使用的是Linux),请阅读此博客文章。edgystuff.tumblr.com/post/49304254688像RavenDB这样开箱即可。
塔米尔,

与这里提到的embedmongo-maven-plugin相似,也有Gradle Mongo插件可用。像Maven插件一样,它也包装了flappoodle EmbeddedMongoDb api,并允许您从Gradle构建中运行Mongo的托管实例。
罗伯特·泰勒

在此处检查此代码示例:github.com/familysyan/embedded-mongo-integ。没有安装,没有依赖关系。它只是一个独立于平台的ant脚本,可以为您进行下载和设置。它也可以在测试后清除所有内容。
艾德蒙(Edmond)

Answers:


9

这是@rozky接受的答案的更新版本(2019年)(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.IMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
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;
        IMongodConfig mongodConfig = new MongodConfigBuilder()
        .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());
    }

}

1
对于每个测试,重复启动和停止Embedded mongo都会使大多数测试失败。最好在所有测试之前启动并执行所有命令后关闭
DBS

您需要包括@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)上述更改
DBS

@DBS您也可以使用随机端口,以便仍可以在新的嵌入式mongo实例上同时运行测试。在这里查看文档。
Collin Krawll '19

95

我发现嵌入式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));
    }
}

1
刚刚使用了这个库,它就可以完美地在Mac上通过JUnit测试Mongo API。推荐的。
马丁·道

1
+1个出色的发现!一年前,当我第一次开始使用mongodb时,它的缺点之一就是没有以编程方式对数据库进行测试。通过在每个环境上都有一个测试实例(通过Java属性文件配置)来解决这个问题,但是当然需要在每个环境上都安装mongo。看起来它将解决所有问题。
andyb 2012年

真好!删除了我的答案,因为它不再准确。有人知道这有多成熟吗?我可以想象它必须在非常低的级别上模拟MongoDB会非常复杂,并且从源头上看,它看起来相当高级。
Remon van Vliet 2012年

最终在我的项目中进行了尝试,并可以报告它非常易于设置和运行。低级调用都是官方com.mongodb Java API的一部分,因此它并不比使用常规API复杂。
andyb

17
请谨慎使用此解决方案。它只是收集有关当前操作系统的信息,并从Internet下载适当的特定于平台的MongoDB二进制文件,运行守护程序并执行其他一些配置工作。作为企业解决方案,事实并非如此。模拟可能是唯一的选择。
詹姆斯·沃特金斯

18

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


1
Fongo是否碰巧拦截了对网络的呼叫(例如,对localhost:27017的呼叫),以便它可以充当嵌入式伪造服务器来启用集成测试而无需更改代码?

mongo-java-server是一种伪造的伪造服务器实现,可用于集成测试而无需更改代码。
Benedikt Waldvogel

7

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

embedmongo-maven-plugin

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

与其他插件相比,使用此插件的真正好处是不需要预先安装MongoDB。MongoDB二进制文件已下载并存储在~/.embedmongo以后的版本中。


这是莱宁根的Clojure版本:github.com/joelittlejohn/lein-embongo
joelittlejohn 2012年


4

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

1
您能解释“ @EnableAutoConfiguration(exclude = {EmbeddedMongoAutoConfiguration.class})注释的实际作用吗?
布鲁诺·内格罗·齐卡(BrunoNegrãoZica)

原因很可能是de.flapdoodle.embed.mongo依赖项未标记为测试范围。不要选择它并在生产应用程序设置中运行嵌入式mongo,这是必需的。
谢尔盖·谢尔巴科夫

3

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

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


1

不仅用于单元测试,还介绍了如何将内存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>

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

application.properties

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

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

UserRepository.java

公共接口UserRepository扩展了MongoRepository {

}

供参考,所有Java代码使用下面的链接:(逐步说明)

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


0

执行时性能更好mongodstorageEngine='ephemeralForTest'

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

-1

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

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

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


6
我想你错过了我的目的。我不是在寻找Mongo的假实例,我想要一个真实的实例,但已嵌入测试中。原因是启动MongoDB并将其置于特定状态,而不污染现有数据库,运行一系列操作,然后检查结果,而无需筛选与测试无关的任意数据。在保持受控测试环境的同时尽可能地真实。
seanhodges

抱歉,单词“ simulate”和所有这些“内存中”建议使我忘记了Java-land中“嵌入式”的含义。听到那个消息很开心。
杰克逊
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.