MongoDB ในตัวเมื่อรันการทดสอบการรวม


112

คำถามของฉันคือการเปลี่ยนแปลงของคนนี้

เนื่องจากโครงการ Java Web-app ของฉันต้องการตัวกรอง / แบบสอบถามและอินเทอร์เฟซสำหรับการอ่านจำนวนมากกับเครื่องมือเช่น GridFS ฉันจึงพยายามคิดหาวิธีที่เหมาะสมในการใช้ MongoDB ตามวิธีที่โซลูชันข้างต้นแนะนำ

ดังนั้นฉันกำลังพิจารณาใช้อินสแตนซ์แบบฝังของ MongoDB ควบคู่ไปกับการทดสอบการรวมระบบของฉัน ฉันต้องการให้เริ่มต้นโดยอัตโนมัติ (ไม่ว่าจะสำหรับการทดสอบแต่ละครั้งหรือทั้งชุด) ล้างฐานข้อมูลสำหรับการทดสอบทุกครั้งและปิดเครื่องในตอนท้าย การทดสอบเหล่านี้อาจทำงานบนเครื่องพัฒนาเช่นเดียวกับเซิร์ฟเวอร์ CI ดังนั้นโซลูชันของฉันจะต้องพกพาได้ด้วย

ใครที่มีความรู้เพิ่มเติมเกี่ยวกับ MongoDB ช่วยให้ฉันทราบถึงความเป็นไปได้ของแนวทางนี้และ / หรืออาจแนะนำเนื้อหาการอ่านที่อาจช่วยให้ฉันเริ่มต้นได้

ฉันยังเปิดรับข้อเสนอแนะอื่น ๆ ที่ผู้คนอาจมีเกี่ยวกับวิธีแก้ไขปัญหานี้ ...


หากคุณใช้ maven คุณสามารถใช้mvnrepository.com/artifact/com.wenzani/mongodb-maven-plugin ของ
markdsievers

คุณยังสามารถตรวจสอบโปรเจ็กต์นี้ซึ่งจำลอง MongoDB ภายในหน่วยความจำ JVM github.com/thiloplanz/jmockmongoแต่ยังอยู่ระหว่างการพัฒนา
Sebastien Lorber

ไม่ใช่ [เฉพาะสำหรับ] สำหรับการทดสอบหน่วย แต่อ่านบล็อกโพสต์นี้หากคุณต้องการเรียกใช้ MongoDB (แม้กระทั่งคลัสเตอร์) เป็นการปรับใช้ในหน่วยความจำหากคุณใช้ Linux edgystuff.tumblr.com/post/49304254688จะดีมากถ้าเอาออกจากกล่องเหมือน RavenDB
Tamir

คล้ายกับ embedmongo-Maven ปลั๊กอินกล่าวถึงที่นี่ยังมีGradle Mongo ปลั๊กอินใช้ได้ เช่นเดียวกับปลั๊กอิน Maven มันยังห่อflapdoodle EmbeddedMongoDb apiและให้คุณเรียกใช้อินสแตนซ์ที่มีการจัดการของ Mongo จาก Gradle builds ของคุณ
Robert Taylor

ตรวจสอบตัวอย่างรหัสนี้ได้ที่นี่: github.com/familysyan/embedded-mongo-integ ไม่มีการติดตั้งไม่มีการพึ่งพา มันเป็นเพียงสคริปต์มดอิสระของแพลตฟอร์มที่ดาวน์โหลดและตั้งค่าให้คุณ นอกจากนี้ยังทำความสะอาดทุกอย่างหลังการทดสอบของคุณ
Edmond

คำตอบ:


9

นี่คือเวอร์ชันอัปเดต (สำหรับปี 2019) ของคำตอบที่ได้รับการยอมรับจาก @rozky (มีการเปลี่ยนแปลงมากมายทั้งในไลบรารี 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
การเริ่มต้นและการหยุดของ mongo แบบฝังซ้ำ ๆ สำหรับการทดสอบแต่ละครั้งล้มเหลวในการทดสอบส่วนใหญ่ จะดีกว่าที่จะเริ่มก่อนการทดสอบและการปิดระบบทั้งหมดเมื่อดำเนินการ
DBS

คุณต้องรวมไว้@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)พร้อมกับการเปลี่ยนแปลงข้างต้น
DBS

@DBS คุณอาจใช้พอร์ตแบบสุ่มเพื่อให้คุณยังคงสามารถเรียกใช้การทดสอบของคุณพร้อมกันกับอินสแตนซ์ mongo ที่ฝังตัวใหม่ได้ ดูเอกสารที่นี่
Collin Krawll

95

ฉันพบไลบรารีMongoDB แบบฝังซึ่งดูมีแนวโน้มดีและทำตามที่คุณขอ

ปัจจุบันรองรับเวอร์ชัน MongoDB: 1.6.5ถึง3.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
เพิ่งใช้ไลบรารีนี้และทำงานได้อย่างสมบูรณ์แบบ JUnit ทดสอบ Mongo API บนเครื่อง Mac แนะนำ.
Martin Dow

1
+1 ยอดเยี่ยม! เมื่อฉันเริ่มใช้ mongodb ครั้งแรกเมื่อปีที่แล้วการไม่มีวิธีทดสอบกับฐานข้อมูลแบบเป็นโปรแกรมถือเป็นข้อเสียอย่างหนึ่ง เราทำได้โดยการมีอินสแตนซ์การทดสอบในทุกสภาพแวดล้อมกำหนดค่าผ่านไฟล์คุณสมบัติ Java แต่แน่นอนว่าจำเป็นต้องติดตั้ง mongo ในทุกสภาพแวดล้อม ดูเหมือนว่ามันจะแก้ปัญหาได้ทั้งหมด
andyb

ดี! ลบคำตอบของฉันเนื่องจากไม่ถูกต้องอีกต่อไป ใคร ๆ ก็คิดว่ามันเป็นผู้ใหญ่แค่ไหน? ฉันสามารถจินตนาการได้ว่าการจำลอง MongoDB ในระดับที่ต่ำมากจะค่อนข้างซับซ้อนและการตัดสินจากแหล่งที่มามันดูค่อนข้างสูง
Remon van Vliet

ในที่สุดก็เล่นกับสิ่งนี้ในโครงการของฉันและสามารถรายงานได้ว่าตั้งค่าและเรียกใช้งานได้ง่ายอย่างเหลือเชื่อ การเรียกระดับต่ำทั้งหมดเป็นส่วนหนึ่งของcom.mongodb Java APIอย่างเป็นทางการดังนั้นจึงไม่ซับซ้อนไปกว่าการใช้ API ปกติ
andyb

17
ระวังด้วยวิธีนี้ เพียงรวบรวมข้อมูลเกี่ยวกับระบบปฏิบัติการปัจจุบันและดาวน์โหลดไบนารี MongoDB เฉพาะแพลตฟอร์มที่เหมาะสมจากอินเทอร์เน็ตเรียกใช้ daemon และทำการกำหนดค่าอื่น ๆ ในฐานะโซลูชันระดับองค์กรนี่ไม่ใช่ การล้อเลียนอาจเป็นทางเลือกเดียวที่แท้จริง
James Watkins

18

มี Foursquare สินค้าFongo Fongo คือการใช้งาน java ในหน่วยความจำของ mongo มันสกัดกั้นการโทรไปยังโปรแกรมควบคุม mongo-java มาตรฐานสำหรับการค้นหาอัพเดตแทรกลบและวิธีการอื่น ๆ การใช้งานหลักมีไว้สำหรับการทดสอบหน่วยน้ำหนักเบาซึ่งคุณไม่ต้องการหมุนกระบวนการ mongo


1
Fongo เกิดขึ้นเพื่อสกัดกั้นการโทรไปยังเครือข่ายหรือไม่เช่นไปยัง localhost: 27017 เพื่อให้สามารถใช้เป็นเซิร์ฟเวอร์ปลอมแบบดรอปอินเพื่อเปิดใช้งานการทดสอบการรวมโดยไม่มีการเปลี่ยนแปลงโค้ด

mongo-java-serverเป็นการใช้งานเซิร์ฟเวอร์ปลอมแบบดรอปอินที่สามารถใช้สำหรับการทดสอบการรวมโดยไม่มีการเปลี่ยนแปลงโค้ด
Benedikt Waldvogel

7

หากคุณใช้ Maven คุณอาจสนใจปลั๊กอินที่ฉันสร้างขึ้นซึ่งห่อหุ้มflapdoodle.de 'ฝังตัว mongo' API :

Embedmongo-maven-plugin

มีstartเป้าหมายที่คุณสามารถใช้เพื่อเริ่ม MongoDB เวอร์ชันใดก็ได้ที่คุณต้องการ (เช่นในระหว่างpre-integration-test) และstopเป้าหมายที่จะหยุด MongoDB (เช่นระหว่างpost-integration-test)

ประโยชน์ที่แท้จริงของการใช้ปลั๊กอินนี้กับคนอื่น ๆ คือไม่มีข้อกำหนดสำหรับการติดตั้ง MongoDB ไว้ก่อน MongoDB ไบนารีจะถูกดาวน์โหลดและเก็บไว้~/.embedmongoเพื่อสร้างในอนาคต


และนี่คือเวอร์ชัน Clojure สำหรับ Leiningen: github.com/joelittlejohn/lein-embongo
joelittlejohn


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})" กำลังทำอะไรอยู่
Bruno Negrão Zica

สาเหตุส่วนใหญ่อาจเป็นเพราะการอ้างอิง de.flapdoodle.embed.mongo ไม่ได้ทำเครื่องหมายสำหรับขอบเขตการทดสอบ ไม่ให้หยิบมันขึ้นมาและเรียกใช้ mongo แบบฝังในการตั้งค่าแอปพลิเคชันการผลิตจำเป็นต้องมีการยกเว้น
Sergey Shcherbakov

3

คุณสามารถเรียกใช้ MongoDB ในหน่วยความจำได้ตั้งแต่เวอร์ชัน 3.2.6 จากเว็บไซต์ :

เริ่มต้นใน MongoDB Enterprise เวอร์ชัน 3.2.6 เอ็นจินหน่วยความจำในหน่วยความจำเป็นส่วนหนึ่งของความพร้อมใช้งานทั่วไป (GA) ในรุ่น 64 บิต นอกเหนือจากข้อมูลเมตาและข้อมูลการวินิจฉัยบางอย่างแล้วเอ็นจินหน่วยความจำในหน่วยความจำจะไม่เก็บรักษาข้อมูลบนดิสก์รวมถึงข้อมูลการกำหนดค่าดัชนีข้อมูลรับรองผู้ใช้ ฯลฯ


1

ไม่เพียง แต่สำหรับการทดสอบหน่วย แต่ยังอธิบายวิธีใช้ mongodb ในหน่วยความจำกับ 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

ผลการดำเนินงานที่ดีขึ้นเมื่อมีการดำเนินการmongodกับstorageEngine='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

ขออภัยคำว่า "จำลอง" และคำแนะนำ "ในหน่วยความจำ" ทั้งหมดนี้ทำให้ฉันลืมความหมายของ "ฝัง" ใน Java-land ดีใจที่ได้ยิน
Jackson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.