Статьи

Интеграционное тестирование выполнено правильно с Embedded MongoDB

Вступление

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

Веб-компоненты могут быть протестированы модульно с использованием сервисов бизнес-логики. Сервисы могут быть проверены на наличие ложных хранилищ данных. Но уровень доступа к данным не является хорошим кандидатом для модульного тестирования , потому что операторы базы данных должны быть проверены на соответствие действующей системе баз данных.

Варианты тестирования базы данных интеграции

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

Урок 1. Нам нужна разветвленная база данных, связанная с набором тестов

При запуске набора тестов база данных должна быть запущена и сделана доступной только для этого конкретного экземпляра набора тестов. В основном у нас есть следующие варианты:

  • Встроенная база данных в памяти
  • Временный порожденный процесс базы данных

Ошибка тестирования базы данных в памяти

Java предлагает на выбор несколько вариантов реляционной базы данных в памяти:

Встраивание базы данных в память происходит быстро, и каждая JVM может запускать свою собственную изолированную базу данных. Но мы больше не тестируем действительный производственный механизм базы данных, потому что наши интеграционные тесты будут проверять поведение приложения для непроизводственной системы баз данных.

Использование инструмента ORM может создать ложное впечатление, что все базы данных равны, особенно когда весь сгенерированный код SQL совместим с SQL-92 .

Что хорошо для поддержки базы данных инструмента ORM, может лишить вас возможности использовать специфичные для базы данных функции запросов ( оконные функции , общие табличные выражения , PIVOT ).

Таким образом, база данных тестирования интеграции в памяти может не поддерживать такие сложные запросы. Это может привести к снижению охвата кода или к тому, что разработчики будут вынуждены использовать только общие, но ограниченные возможности SQL-запросов.

Даже если ваше ядро ​​производственной базы данных предоставляет вариант в памяти , могут существовать рабочие различия между действительной и облегченной версиями базы данных.

Урок 2. Базы данных в памяти могут создать ложное впечатление о том, что ваш код также будет работать в рабочей базе данных

Создание производственной временной базы данных

Тестирование на реальной производственной базе данных гораздо более ценно, и именно поэтому я вырос, чтобы оценить эту альтернативу.

При использовании MongoDB мы можем выбрать встроенный плагин Монго . Этот проект с открытым исходным кодом создает процесс внешней базы данных, который может быть связан с текущим жизненным циклом набора тестов.

Если вы используете Maven, вы можете воспользоваться модулем embedmongo-maven-plugin :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<plugin>
    <groupId>com.github.joelittlejohn.embedmongo</groupId>
    <artifactId>embedmongo-maven-plugin</artifactId>
    <version>${embedmongo.plugin.version}</version>
    <executions>
        <execution>
            <id>start</id>
            <goals>
                <goal>start</goal>
            </goals>
            <configuration>
                <port>${embedmongo.port}</port>
                <version>${mongo.test.version}</version>
                <databaseDirectory>${project.build.directory}/mongotest</databaseDirectory>
                <bindIp>127.0.0.1</bindIp>
            </configuration>
        </execution>
        <execution>
            <id>stop</id>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

При запуске плагина выполняются следующие действия:

  1. Пакет MongoDB загружается:
    1
    2
    3
    4
    5
    [INFO] --- embedmongo-maven-plugin:0.1.12:start (start) @ mongodb-facts ---
    Download Version{2.6.1}:Windows:B64 START
    Download Version{2.6.1}:Windows:B64 DownloadSize: 135999092
    Download Version{2.6.1}:Windows:B64 0% 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 15% 16% 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 29% 30% 31% 32% 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 43% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% 99% 100% Download Version{2.6.1}:Windows:B64 downloaded with 3320kb/s
    Download Version{2.6.1}:Windows:B64 DONE
  2. После запуска нового набора тестов пакет MongoDB распаковывается в уникальном месте во временной папке ОС.
    1
    2
    Extract C:\Users\vlad\.embedmongo\win32\mongodb-win32-x86_64-2008plus-2.6.1.zip START
    Extract C:\Users\vlad\.embedmongo\win32\mongodb-win32-x86_64-2008plus-2.6.1.zip DONE
  3. Встроенный экземпляр MongoDB запущен.
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [mongod output]note: noprealloc may hurt performance in many applications
    [mongod output] 2014-10-09T23:25:16.889+0300 [DataFileSync] warning: --syncdelay 0 is not recommended and can have strange performance
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] MongoDB starting : pid=2384 port=51567 dbpath=D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest 64-bit host=VLAD
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] db version v2.6.1
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] git version: 4b95b086d2374bdcfcdf2249272fb552c9c726e8
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] allocator: system
    [mongod output] 2014-10-09T23:25:16.891+0300 [initandlisten] options: { net: { bindIp: "127.0.0.1", http: { enabled: false }, port: 51567 }, security: { authorization: "disabled" }, storage: { dbPath: "D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest", journal: { enabled: false }, preallocDataFiles: false, smallFiles: true, syncPeriodSecs: 0.0 } }
    [mongod output] 2014-10-09T23:25:17.179+0300 [FileAllocator] allocating new datafile D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest\local.ns, filling with zeroes...
    [mongod output] 2014-10-09T23:25:17.179+0300 [FileAllocator] creating directory D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest\_tmp
    [mongod output] 2014-10-09T23:25:17.240+0300 [FileAllocator] done allocating datafile D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest\local.ns, size: 16MB,  took 0.059 secs
    [mongod output] 2014-10-09T23:25:17.240+0300 [FileAllocator] allocating new datafile D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest\local.0, filling with zeroes...
    [mongod output] 2014-10-09T23:25:17.262+0300 [FileAllocator] done allocating datafile D:\wrk\vladmihalcea\vladmihalcea.wordpress.com\mongodb-facts\target\mongotest\local.0, size: 16MB,  took 0.021 secs
    [mongod output] 2014-10-09T23:25:17.262+0300 [initandlisten] build index on: local.startup_log properties: { v: 1, key: { _id: 1 }, name: "_id_", ns: "local.startup_log" }
    [mongod output] 2014-10-09T23:25:17.262+0300 [initandlisten]     added index to empty collection
    [mongod output] 2014-10-09T23:25:17.263+0300 [initandlisten] waiting for connections on port 51567
    [mongod output] Oct 09, 2014 11:25:17 PM MongodExecutable start
    INFO: de.flapdoodle.embed.mongo.config.MongodConfigBuilder$ImmutableMongodConfig@26b3719c
  4. Для срока службы текущего набора тестов вы можете увидеть процесс embedded-mongo:
    1
    2
    3
    4
    5
    6
    7
    8
    C:\Users\vlad>netstat -ano | findstr 51567
      TCP    127.0.0.1:51567        0.0.0.0:0              LISTENING       8500
       
    C:\Users\vlad>TASKLIST /FI "PID eq 8500"
     
    Image Name                     PID Session Name        Session#    Mem Usage
    ========================= ======== ================ =========== ============
    extract-0eecee01-117b-4d2     8500 RDP-Tcp#0                  1     44,532 K

    встраивать-Монго

  5. Когда тестовый набор завершен, монтирование встраивается
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    [INFO] --- embedmongo-maven-plugin:0.1.12:stop (stop) @ mongodb-facts ---
    2014-10-09T23:25:21.187+0300 [initandlisten] connection accepted from 127.0.0.1:64117 #11 (1 connection now open)
    [mongod output] 2014-10-09T23:25:21.189+0300 [conn11] terminating, shutdown command received
    [mongod output] 2014-10-09T23:25:21.189+0300 [conn11] dbexit: shutdown called
    [mongod output] 2014-10-09T23:25:21.189+0300 [conn11] shutdown: going to close listening sockets...
    [mongod output] 2014-10-09T23:25:21.189+0300 [conn11] closing listening socket: 520
    [mongod output] 2014-10-09T23:25:21.189+0300 [conn11] shutdown: going to flush diaglog...
    [mongod output] 2014-10-09T23:25:21.189+0300 [conn11] shutdown: going to close sockets...
    [mongod output] 2014-10-09T23:25:21.190+0300 [conn11] shutdown: waiting for fs preallocator...
    [mongod output] 2014-10-09T23:25:21.190+0300 [conn11] shutdown: closing all files...
    [mongod output] 2014-10-09T23:25:21.191+0300 [conn11] closeAllFiles() finished
    [mongod output] 2014-10-09T23:25:21.191+0300 [conn11] shutdown: removing fs lock...
    [mongod output] 2014-10-09T23:25:21.191+0300 [conn11] dbexit: really exiting now
    [mongod output] Oct 09, 2014 11:25:21 PM de.flapdoodle.embed.process.runtime.ProcessControl stopOrDestroyProcess

Вывод

Плагин embed-mongo нигде не медленнее, чем любые системы баз данных отношений в памяти. Меня удивляет, почему нет такой опции для СУБД с открытым исходным кодом (например, PostgreSQL). Это отличная идея проекта с открытым исходным кодом, и, возможно, Flapdoodle OSS также предложит поддержку реляционных баз данных.

  • Код доступен на GitHub .