Зачем использовать базу данных в памяти для интеграционного тестирования?

18

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

Что мне здесь не хватает?

dnang
источник
Я видел это много, потому что вы можете программно обеспечить согласованность данных, плюс они обычно достаточно быстрые. Особенно, если ваш тест является юнит-тестом, вы хотите, чтобы это была закрытая система. Вы хотите, чтобы ваши тесты были полностью включены в тест.
Буровая установка
Приятно, что разработчик может получить последнюю версию всего кода и запустить тесты без предварительной настройки внешней базы данных.
Джейсон Эванс
1
По моему мнению, аспекты, которые должны быть очень похожи на производственную среду, относятся к нагрузочному тестированию и нагрузочному тестированию, которые должны выполняться отдельно от модульного тестирования (которое является критерием фиксации кода).
13

Ответы:

19

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

Первая ситуация, запуск тестов во время разработки, служит краткосрочным целям: определение задач (как в TDD: написать неудачный тест, затем выполнить его), предотвращение регрессий, обеспечение того, чтобы ваши изменения не нарушали ничего другого и т. Д. тесты должны быть чрезвычайно быстрыми: в идеале весь ваш набор тестов выполняется менее чем за 5 секунд, и вы можете просто запустить его в цикле рядом с вашей IDE или текстовым редактором во время кодирования. Любая регрессия, которую вы вводите, появится в течение нескольких секунд. Быстрые тестовые прогоны на этом этапе важнее, чем выявление 100% регрессий и ошибок, и поскольку практически невозможно (или просто невозможно) разрабатывать точные копии производственных систем, усилия, необходимые для достижения идеального тестирования, здесь не стоят Это. Использование баз данных в памяти является компромиссом: они не являются точными копиями производственной системы, но они помогают держать тестовые прогоны ниже 5-секундного предела; если выбор между немного другой настройкой базы данных для моего тестирования, связанного с базой данных, и вообще без тестирования, я знаю, что выберу.

Вторая ситуация, перемещение кода по цепочке развития, однако, делает требует тщательного тестирования. Поскольку мы можем (и должны) автоматизировать эту часть процесса разработки, мы можем позволить себе гораздо более медленные тесты - даже если полный запуск теста занимает часы, планирование ночной сборки все еще означает, что у нас всегда есть точная картина вчерашней кодовой базы. Сейчас важно максимально точно моделировать производственную среду, но мы можем себе это позволить. Поэтому мы не делаем компромисс между базой данных в памяти: мы устанавливаем точно такую ​​же версию той же СУБД, что и производственные системы, и, если возможно, заполняем ее фактическими производственными данными до начала тестирования.

tdammers
источник
6

Я предполагаю, что это компромиссная скорость / соответствие окружающей среде. Тесты должны проводиться часто, а это значит, что они должны быть быстрыми. Особенно юнит-тесты, которые не должны занимать более нескольких секунд.

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

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

Лоран Бурго-Рой
источник
3

Для выполнения простых тестов вполне допустимо использование уровня доступа к базе данных. Вы звоните getName(), он вызывает DAO, который был высмеян, и возвращает «Джон» для имени и «Смит» для фамилии, собирает их, и все идеально. Нет необходимости тестировать базу данных там.

Все становится немного больше, когда логика становится немного сложнее. Что делать, если у вас был метод "createOrUpdateUser (...)". Если вы смоделировали базу данных, вы можете проверить, что данный метод был вызван один раз с определенным параметром, когда макет не возвращает объектов, и другой метод вызывается в базе данных, когда он возвращает обратно существующий объект. Это начинает переходить к этой нечеткой строке, где может быть проще (особенно если оно уже было) развернуть специализированную базу данных в памяти и протестировать этот код с предварительно сконфигурированными данными.

В каком-то реальном коде, над которым я работал (точка продаж), у нас был resumeSuspededTransaction(...)метод. Это вытянет транзакцию из базы данных в объект (и его компоненты) и обновит базу данных. Мы высмеяли его, и где-то в коде скрывалась ошибка с сериализацией и десериализацией данных, поступающих в базу данных (мы изменили тип, который по-разному сериализовался в базе данных).

Макет не показал нам ошибку, потому что он возвращал свой счастливый путь - сериализовать транзакцию, сохранить ее в макете, десериализовать ее из макета, проверить, что они равны. Однако, когда вы сериализуете объект с начальным нулем в базе данных, он отбрасывает их, а затем рекомбинирует обратно в строку без нулей. Мы обнаружили ошибку без базы данных путем устранения неполадок (это было не так сложно обнаружить, когда мы узнали, что это было там).

Позже мы поместили туда базу данных и поняли, что ошибка не прошла бы через этот тест junit, если бы мы вместо этого шли в базу данных в памяти.


В базах данных памяти есть свои преимущества:

  • их можно быстро раскрутить (без необходимости администратора базы данных для настройки учетных записей, таблиц и т. д.) для тестирования
  • данные могут быть предварительно настроены для этого теста
  • тесту не нужно беспокоиться об откате теста после его завершения
  • Каждый тест имеет свою базу данных в памяти, поэтому вам не нужно беспокоиться, если два теста выполняются одновременно
  • они могут быть запущены в системах, которые не имеют подключения к реальным базам данных

источник
1

Это во многом зависит от системы баз данных, которую вы используете. Когда ваша система БД предоставляет вам альтернативу в памяти, которая почти на 100% API и поведение, совместимое с конфигурацией базы данных на диске (за исключением скорости и надежности, или курса), тогда использование варианта в памяти, очевидно, хорошо ,

Однако, если ваша система БД имеет существенные различия между конфигурацией в памяти и использованием не в памяти, вы правы: в этом случае интеграционные тесты имеют более высокий риск скрытия ошибки. Но даже в этом случае вы можете самостоятельно «абстрагироваться от этих различий», если вы хорошо знаете свою систему БД и эти различия.

Док Браун
источник
1

По словам непрофессионала:

Насмешка над важными частями архитектуры в порядке (и обязательна) для модульного тестирования .

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

В конце концов, интеграционные тесты - это тестирование того, как различные части архитектуры ведут себя вместе.

Тулаинс Кордова
источник