Вбудований MongoDB при запуску інтеграційних тестів


112

Моє запитання - це варіація цього .

Оскільки мій проект для веб-додатків Java потребує великої кількості фільтрів / запитів для читання та інтерфейсів з такими інструментами, як GridFS, я намагаюся думати про розумний спосіб використання MongoDB у спосіб, запропонований вище.

Тому я розглядаю можливість запуску вбудованого примірника MongoDB поряд із моїми інтеграційними тестами. Я хотів би, щоб він запускався автоматично (або для кожного тесту, або для всього набору), промивав базу даних для кожного тесту і закривав наприкінці. Ці тести можуть бути запущені як на розробниках, так і на сервері CI, тому моє рішення також повинно бути портативним .

Чи може хтось, хто має більше знань про MongoDB, допомогти мені зрозуміти доцільність такого підходу та / або, можливо, запропонувати будь-який матеріал для читання, який може допомогти мені почати роботу?

Я також відкритий для інших пропозицій людей щодо того, як я можу підійти до цієї проблеми ...


Якщо ви використовуєте maven, ви можете використовувати наш mvnrepository.com/artifact/com.wenzani/mongodb-maven-plugin
markdsievers

Ви також можете перевірити цей проект, який імітує MongoDB всередині пам'яті JVM. github.com/thiloplanz/jmockmongo Але він ще розвивається.
Себастьян Лорбер

Не [лише для] тестування одиниць, але прочитайте цю публікацію в блозі, якщо ви хочете запустити MongoDB (навіть кластер) як розгортання в пам'яті, якщо ви використовуєте Linux. edgystuff.tumblr.com/post/49304254688 Було б чудово, щоб це було не в коробці, як RavenDB.
Тамір

Подібно до згаданого тут плагіна embedmongo-maven, також доступний плагін Gradle Mongo . Як і плагін Maven, він також загортає app flapdoodle EmbeddedMongoDb і дозволяє запускати керований екземпляр Mongo зі своїх будівель Gradle.
Роберт Тейлор

Перевірте цей приклад коду тут: github.com/familysyan/embedded-mongo-integ . Ні установки, ні залежності. Це просто незалежний від платформи мурашиний сценарій, який завантажує та налаштовує для вас. Він також очищає все після ваших тестів.
Едмонд

Відповіді:


9

Ось оновлена ​​(на 2019 рік) версія прийнятої відповіді від @rozky (багато було змінено як у бібліотеках Mongo, так і вбудованих 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
Повторний запуск і зупинка вбудованого монго для кожного тесту не дає більшості тестів. Краще розпочати перед усіма тестами та відключенням після того, як всі будуть виконані
DBS

Вам потрібно включити @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)разом із зазначеною вище зміною
DBS

@DBS Ви можете також використовувати випадковий порт, щоб ви все одно могли запускати свої тести одночасно на вбудованому екземплярі монго. Дивіться документи тут .
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 тестуючи API Mongo на Mac. Рекомендовано
Мартін Дау

1
+1 відмінна знахідка! Коли я вперше почав використовувати mongodb рік тому, відсутність програмного способу тестування на базу даних був одним із мінусів. Ми вирішили це шляхом тестового примірника для кожного середовища, налаштованого через файл властивостей Java, але, звичайно, для встановлення mongo у кожному середовищі. Схоже, це все вирішить.
andyb

Приємно! видалили мою відповідь, оскільки вона вже не є точною. Хтось має ідею, наскільки це зріло? Я можу уявити, що необхідність імітувати MongoDB на дуже низькому рівні була б досить складною, і судячи з джерела, це виглядає досить високим рівнем.
Ремон ван Вліт

Нарешті, я можу зіграти з цим у своєму проекті і можу повідомити, що це було надзвичайно просто налаштувати та запустити. Дзвінки низького рівня - це частина офіційного com.mongodb Java API, тому це не складніше, ніж використання звичайного API.
andyb

17
Будьте обережні з цим рішенням. Він просто збирає інформацію про поточну операційну систему та завантажує з Інтернету відповідні для платформи бінарні файли MongoDB, запускає демон і виконує деякі інші налаштування. Як рішення для підприємства, це не так. Знущання може бути єдиним реальним варіантом.
Джеймс Уоткінс

18

Існує продукт Foursquare Fongo . Fongo - це реалізація монго в java-пам'яті. Він перехоплює дзвінки до стандартного драйвера mongo-java для пошуку, оновлення, вставки, видалення та інших методів. Основне використання - для тестування легких одиниць, де ви не хочете розкручувати процес mongo.


1
Чи трапляється, що Fongo перехоплює дзвінки в мережу, наприклад, до localhost: 27017, щоб він міг слугувати як підробний підроблений сервер для включення тестування інтеграції без зміни коду?

mongo-java-сервер - це підроблена реалізація підроблених серверів, яку можна використовувати для тестування інтеграції без зміни коду.
Бенедікт Вальдвогель

7

Якщо ви використовуєте Maven, можливо, вас зацікавить створений я плагін, який обгортає API flapdoodle.de 'embedded mongo' :

embedmongo-maven-плагін

Він забезпечує 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

пом.хмл

<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 (виключити = {EmbeddedMongoAutoConfiguration.class})"?
Бруно Неграо Зіка

Причиною є, ймовірно, залежність de.flapdoodle.embed.mongo, не позначена для тестової області. Щоб не брати його і не запускати вбудований монго в налаштування виробничих додатків, потрібно виключення.
Сергій Щербаков

3

Ви можете запустити MongoDB в пам'яті, починаючи з версії 3.2.6. З сайту :

Починаючи з версії 3.2.6 MongoDB Enterprise, двигун пам’яті пам’яті є частиною загальної доступності (GA) у 64-бітних збірках. Окрім деяких метаданих та діагностичних даних, механізм зберігання в пам'яті не підтримує жодних даних на диску, включаючи дані конфігурації, індекси, облікові дані користувачів тощо.


1

Не тільки для одиничного тестування, але також пояснив, як використовувати пам’ятний монгобб з спокою 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

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

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
Я думаю, ти пропустив моє призначення. Я не шукав фальшивий екземпляр Монго, я хотів справжній екземпляр, але вкладений у свої тести. Причина полягала в тому, щоб запустити MongoDB і перевести його у певний стан, не забруднюючи існуючу базу даних, виконати ряд операцій, а потім перевірити результат, не потребуючи просіювати довільні дані, які не стосувалися мого тесту. Настільки реально, наскільки це можливо, поки зберігається контрольоване тестове середовище.
seanhodges

Вибачте, слово "імітувати" і всі ці пропозиції "в пам'яті" змусили мене забути значення "вбудований" у Java-землю. Радий це чути.
Джексон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.