Как написать модульный тест базы данных?

Я использую MongoDB, Java, JDO и Maven.

Я запустил простое основное приложение, которое хранит некоторые ненужные данные и извлекает их из mongodb, и все выглядит нормально, но я хочу начать писать правильные модульные тесты. Моделирование фактического взаимодействия с базой данных не кажется мне очень полезным, поэтому технически я хочу написать функциональные тесты, которые проверяют полное взаимодействие с базой данных.

Мой модульный тест настроен следующим образом:

static final Logger LOG = LoggerFactory.getLogger(DaoTest.class);
static final int PORT = 100001;
static Process mongod;
static PersistenceManagerFactory pmf;

// Class under test.
Dao dao;

@BeforeClass
public static void beforeAll() throws Exception {
  File mongoDir = new File(
      System.getProperty("java.io.tmpdir"),
      "mongodb-" + System.currentTimeMillis());
  mongoDir.deleteOnExit();
  mongod = Runtime.getRuntime().exec(String.format(
      "/bin/sh -c mongod --dbpath=%s --port=%d",
      mongoDir.getAbsolutePath(),
      PORT));
  LOG.info("Mongodb using {} on port {}.", mongoDir.getAbsolutePath(), PORT);
  Thread.sleep(1000);
  pmf = JDOHelper.getPersistenceManagerFactory("mongodbtest");
  LOG.info("DB connection URL: {}.", pmf.getConnectionURL());
}

@AfterClass
public static void afterAll() throws Exception {
  mongod.destroy();
}

@Before
public void setUp() throws Exception {
  dao = new Dao(pmf);
}

src/test/resources/META-INF/persistence.xml выглядит так:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence ...>
  <persistence-unit name="mongodbtest">
    <properties>
      <property name="javax.jdo.PersistenceManagerFactoryClass"
          value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory" />
      <property name="javax.jdo.option.ConnectionURL" value="mongodb://localhost:100001/contacts"/>
      <property name="javax.jdo.option.RetainValues" value="true"/>
      <property name="datanucleus.autoCreateSchema" value="true" />
      <property name="datanucleus.validateTables" value="false" />
      <property name="datanucleus.validateConstraints" value="false" />
      <property name="datanucleus.storeManagerType" value="mongodb" />
    </properties>
  </persistence-unit>
</persistence>

И, наконец, я выполняю свой модульный тест с mvn clean test, и только он будет работать, пока я не добавлю фактический тест, который пытается сохранить данные. Я получаю следующую ошибку:

Mongodb using /var/folders/00/0l550000h01000cxqpysvccm002cmm/T/mongodb-1373820849219 on port 100001.
DB connection URL: mongodb://localhost:100001/contacts.
Jul 14, 2013 12:54:10 PM com.mongodb.DBTCPConnector initDirectConnection
WARNING: Exception executing isMaster command on localhost/127.0.0.1:27017
java.io.IOException: couldn't connect to [localhost/127.0.0.1:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:214)
    at com.mongodb.DBPort.go(DBPort.java:107)

...

Jul 14, 2013 12:54:10 PM com.mongodb.DBTCPConnector initDirectConnection
WARNING: Exception executing isMaster command on localhost/127.0.0.1:27017
java.io.IOException: couldn't connect to [localhost/127.0.0.1:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:214)
    at com.mongodb.DBPort.go(DBPort.java:107)

...

ul 14, 2013 12:54:10 PM com.mongodb.DBPortPool gotError
WARNING: emptying DBPortPool to localhost/127.0.0.1:27017 b/c of error
java.io.IOException: couldn't connect to [localhost/127.0.0.1:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:214)
    at com.mongodb.DBPort.go(DBPort.java:107)

...

Jul 14, 2013 12:54:10 PM org.datanucleus.store.valuegenerator.AbstractGenerator obtainGenerationBlock
INFO: Error encountered allocating block of IDs : can't call something : localhost/127.0.0.1:27017//localhost:100001/contacts

127.0.0.1:27017 — это настройки mongodb по умолчанию, но я понятия не имею, почему он их использует. Я вижу, что он собирает конфигурации из моего файла persistence.xml, поэтому я сбит с толку. документы mongo говорят, что формат URL-адреса строки подключения:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

До сих пор я запускал это только через maven, потому что это только то, что я дошел до сих пор, но в конечном итоге у меня возникнет еще один вопрос: как запускать эти модульные тесты в Eclipse. Я предполагаю, что для запуска этих тестов в Eclipse должен произойти процесс улучшения байтового кода, и я не знаю, как это настроить.

Я предполагаю, что я не первый человек, который хочет сделать что-то подобное. Существуют ли какие-либо стандартные методы написания функциональных тестов базы данных на Java? Я все делаю неправильно?


person Frank Flannigan    schedule 14.07.2013    source источник
comment
вы взглянули на nosql-unit/jongo? Я думаю, что это лучшее решение, чем запускать mongod из java-кода.   -  person Miguel Cartagena    schedule 15.07.2013


Ответы (3)


Чтобы ответить на мой собственный вопрос. Было три вопроса:

1) Строка подключения должна была быть:

mongo:/127.0.0.1/contacts

(обратите внимание на один меньше "/")

2) мне нужно было добавить mongoDir.mkdir();

3) Команда запуска сервера должна быть

String command = String.format(
    "/bin/sh -c mongod --dbpath=%s --port=%d", 
    mongoDir.getAbsolutePath(), 
    PORT);
Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command });

На самом деле я создал для этого JUnit4 Runner, чтобы иметь одну и ту же базу данных во всех тестах и ​​оставил на усмотрение отдельных тестов управление состоянием этой базы данных.

person Frank Flannigan    schedule 15.07.2013

Если вы хотите запустить экземпляр базы данных для тестирования (который работает только во время работы вашей сборки Maven), вам может быть интересен подключаемый модуль Maven, который я написал на основе API-интерфейса Flapdoodle Embedded Mongo:

плагин для встраивания mongo-maven

Одним из преимуществ является то, что плагин автоматически загружает дистрибутив Mongo, поэтому людям не нужно устанавливать Mongo, прежде чем они смогут запустить вашу сборку Maven. Также легко перейти на другую версию Mongo; вы просто меняете конфигурацию плагина.

person joelittlejohn    schedule 17.07.2013

Подумайте о своей цели I ran a simple main application that stores some junk data and retrieves it from mongodb and it looks ok, but I want to start writing proper unit tests.

Если вы работаете в команде, вы обнаружите проблему с текущим исходным кодом. Что делать, если другой член вашей команды использует промежуточную базу данных? Это сделает ваши данные бесполезными, непоследовательными и болезненными для воспроизведения ошибки, связанной с db.

Я думаю, что решение от @joelittlejohn лучше. Используйте встроенный mongo в своем проекте. В настоящее время я использую https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo для моего проекта. Вы можете делать что угодно со своим монго без каких-либо колебаний. Потому что это просто происходит, когда вы запускаете тест.

person Tri Asmoro    schedule 16.07.2018