Встроенный MongoDB при запуске интеграционных тестов
Мой вопрос является вариацией этого.
Поскольку моему проекту Java-веб-приложения требуется много фильтров / запросов на чтение и интерфейсов с такими инструментами, как GridFS, я изо всех сил пытаюсь придумать разумный способ использования MongoDB так, как предлагает вышеупомянутое решение.
Поэтому я рассматриваю возможность запуска встроенного экземпляра MongoDB вместе с моими интеграционными тестами. Я бы хотел, чтобы он запускался автоматически (для каждого теста или всего пакета), очищал базу данных для каждого теста и завершал работу в конце. Эти тесты могут выполняться на машинах разработки, а также на сервере CI, поэтому мое решение также должно быть переносимым.
Может ли кто-нибудь с большим знанием MongoDB помочь мне понять целесообразность такого подхода и / или, возможно, предложить какой-либо материал для чтения, который мог бы помочь мне начать?
Я также открыт для других предложений людей о том, как я могу подойти к этой проблеме...
16 ответов
Я нашел встроенную библиотеку 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));
}
}
Вот обновленная (для 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());
}
}
Существует продукт Foursquare Fongo. Фонго - это Java-реализация Монго в памяти. Он перехватывает вызовы стандартного драйвера mongo-java для поиска, обновления, вставки, удаления и других методов. Основное использование - для легкого модульного тестирования, когда вы не хотите ускорять процесс монго.
Если вы используете Maven, вас может заинтересовать плагин, который я создал, который оборачивает API-интерфейс flapdoodle.de 'embedded mongo':
embedmongo-Maven-плагин
Это обеспечивает start
цель, которую вы можете использовать, чтобы запустить любую версию MongoDB, которую вы хотите (например, во время pre-integration-test
) и stop
цель, которая остановит MongoDB (например, во время post-integration-test
).
Реальное преимущество использования этого плагина перед другими заключается в том, что нет необходимости предварительно устанавливать MongoDB. Бинарные файлы MongoDB загружаются и хранятся в ~/.embedmongo
для будущих сборок.
Если вы используете sbt и specs2, я написал такую же оболочку для embedmongo
С весенней загрузкой 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{
}
Вы можете запустить MongoDB в памяти начиная с версии 3.2.6. С сайта:
Начиная с MongoDB Enterprise версии 3.2.6, механизм хранения в памяти является частью общей доступности (GA) в 64-разрядных сборках. Помимо некоторых метаданных и диагностических данных, механизм хранения в памяти не поддерживает никаких данных на диске, включая данные конфигурации, индексы, учетные данные пользователя и т. Д.
Если вы используете Maven, вы можете использовать наш http://mvnrepository.com/artifact/com.wenzani/mongodb-maven-plugin
Не только для модульных тестов, но и для чтения этого поста в блоге, если вы хотите использовать MongoDB (даже кластер) в качестве развертывания в памяти, если вы используете Linux.
http://edgystuff.tumblr.com/post/49304254688
Было бы здорово иметь его из коробки, как RavenDB, хотя.
Не только для модульного тестирования, но также объяснил, как использовать 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>
================================================== ===========================
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 используйте ссылку ниже:(пошаговое объяснение)
Вы также можете проверить этот проект, который имитирует MongoDB в памяти JVM. https://github.com/thiloplanz/jmockmongo Но он все еще находится в разработке.
Подобно плагину embedmongo-maven-plugin, упомянутому здесь, существует также плагин Gradle Mongo.
Как и плагин Maven, он также оборачивает API-интерфейс flapdoodle EmbeddedMongoDb и позволяет запускать управляемый экземпляр Mongo из ваших сборок Gradle.
Спектакли лучше при исполнении mongod
с участием storageEngine='ephemeralForTest'
new MongodConfigBuilder()
.version(Version.Main.PRODUCTION)
.cmdOptions(new MongoCmdOptionsBuilder()
.useStorageEngine("ephemeralForTest")
.build())
.net(new Net("localhost", port, Network.localhostIsIPv6()))
.build()
Проверьте этот пример кода здесь: https://github.com/familysyan/embedded-mongo-integ. Нет установки, нет зависимости. Это просто независимый от платформы ant-скрипт, который делает загрузку и настройку для вас. Это также убирает все после ваших тестов.
Для запуска Embedded 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
В производстве вы будете использовать реальную базу данных.
Если вы хотите, чтобы ваши тесты отражали поведение вашего продукта в производстве, используйте реальный экземпляр Mongo.
Ложная реализация может вести себя не так, как настоящая. При тестировании вы должны стремиться к правильности. Скорость исполнения занимает второе место.