Базы данных и модульное / интеграционное тестирование

25

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

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

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

  1. На этапе «настройки» перед тем, как тест будет запущен, вы сначала усекаете все таблицы в базе данных.
  2. Затем вы вставляете все данные, необходимые для тестовых случаев, которые вы собираетесь запустить
  3. Затем вы запускаете и проверяете тестовые случаи
  4. Затем в фазе «разрыва» вы снова усекаете все таблицы в базе данных.

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

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

ryanzec
источник

Ответы:

21

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

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

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

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

Николас Мейн
источник
Я просто уверен, что разница между модульным тестированием и интеграционным тестированием, кроме того, я слышал, что блок должен использовать макетированные данные, а интеграция должна использовать базу данных (запустил другой поток programmers.stackexchange.com/questions/101300/… чтобы выяснить разницу ). Кроме этого, все, что вы говорите, кажется, соответствует тому, что я думаю.
ryanzec
Нет проблем, я добавил больше информации к вашему другому ответу
Николас Мэйн
1
почему вы не можете провести модульное тестирование БД? Если вы поместите свой SQL в хранимые процедуры, вы можете выполнить их модульное тестирование с данными, определенными для тестирования, и вдруг все будет просто. Это определенно лучшая практика, которой должны следовать больше людей, посмотрите, что говорит MS
gbjbaanb
1
integration tests- что вы имеете в виду? Как я уже упоминал, модули, использующие базу данных, могут и должны быть протестированы с помощью модульных тестов. База данных может быть изменена вручную или заменена реализацией в памяти
Хеллбой,
6

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

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

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

Paddyslacker
источник
2

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

Вы правы в том, как должны быть написаны тесты, за исключением того, что я бы ничего не урезал:

  • фаза настройки: получить соединение с базой данных и вставить данные
  • фаза запуска
  • фаза разрыва: удалить вставленные данные (усечь)

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

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

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

Пример: проверка таблицы транзакций по счету

  1. Разве вы не хотите проверить просмотр этой таблицы для пользователя / учетной записи без транзакций?
  2. Протестируйте добавление первой записи и посмотрите, сможете ли вы создать баланс.
  3. Создайте записи, когда они уже существуют, и проверьте текущий баланс и любые другие бизнес-правила.
  4. Посмотреть таблицу с существующими записями и все остальные CRUD.

Добьетесь ли вы этого, выполнив шаги 1 и 2 или начав с базы данных, уже находящейся в этом состоянии (восстановить резервную копию?), Я не уверен, что это имеет значение. Ваша идея написания сценариев для меня упрощает управление любыми необходимыми изменениями (например, если вы забыли создать учетную запись администратора и нуждаетесь в ней для нового пользователя). Файлы сценариев легче поместить в систему контроля версий, чем некоторые резервные файлы. Это также зависит от того, распространяете ли вы это приложение.

JeffO
источник
0

Чтобы нарисовать аспекты нескольких ответов вместе и добавить мой 2p ...

Примечание: мои комментарии касаются, в частности , тестирования базы данных , а не тестирования пользовательского интерфейса (хотя очевидно, что аналогичное применимо).

Базы данных так же нуждаются в тестировании, как и интерфейсные приложения, но, как правило, тестируются на основе «работает ли он с интерфейсом?» или «отчеты дают правильный результат?», который, по моему мнению, тестируется очень поздно в процессе разработки базы данных и не очень надежен.

У нас есть ряд клиентов, которые используют модульное / интеграционное / системное тестирование для своей базы данных хранилища данных в дополнение к обычному UAT / performance / et al. тесты. Они обнаружили, что с помощью непрерывной интеграции и автоматизированного тестирования они сталкиваются со многими проблемами, прежде чем переходить к традиционному UAT, что экономит время в UAT и увеличивает шансы на успех UAT.

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

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

Таким образом, давая некоторый контекст для моего ответа ...

Модульное тестирование

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

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

  • проверка схемы, некоторые могут назвать это тестом «контракт с данными»
  • значения столбца, проходящие через
  • использование логических путей с различными значениями данных для функций, процедур, представлений, вычисляемых столбцов
  • тестирование крайнего случая - NULL, неверные данные, отрицательные числа, слишком большие значения

(Блок) интеграционное тестирование

Я нашел этот пост SE полезным в разговоре о различных типах тестирования.

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

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

Затем он переходит к системному тестированию , тестированию системной интеграции (он же конец-2-end тестирование) с увеличением объемов данных и увеличением объема. Все эти тесты должны стать частью системы регрессионного тестирования. Некоторые из этих тестов могут быть выбраны пользователями для выполнения в рамках UAT, но UAT - это тесты, определенные пользователями , а не как они определены ИТ-отделом - обычная проблема!

Итак, теперь, когда я дал некоторый контекст, чтобы ответить на ваши актуальные вопросы

  • предварительное заполнение данных для модульного и интеграционного тестирования может привести к ложным ошибкам тестирования, и его следует избегать.
  • Единственный способ обеспечить непротиворечивые тесты - не делать предположений об исходных данных и тщательно их контролировать.
  • важен отдельный контекст выполнения теста, чтобы гарантировать, что один тестер не конфликтует с другим тестером, выполняющим те же тесты в другой ветви кода базы данных, контролируемой исходным кодом.
Маркус Д
источник
-3

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

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

HLGEM
источник
Я не предлагаю работать с пустой базой данных, если вы видите шаг 2, у меня есть «Затем вы вставляете все данные, необходимые для тестовых случаев, которые вы собираетесь запустить». Что касается проблемы производительности, я не думаю, что это то, для чего предназначено модульное тестирование, это больше нагрузочное тестирование. Модульное тестирование для меня, чтобы проверить, чтобы убедиться, что логика в вашем коде работает. если логика работает, она будет работать для 1 записи или 100 000 000 000 записей с теми же основными данными (хотя это будет намного медленнее).
ryanzec
Запросы к базе данных не просто логичны, и чем раньше вы обнаружите, что они не будут работать в Prod, тем лучше. То, что работает для 1 записи, часто будет зависеть от времени ожидания, и модульный тест должен показать это как можно скорее.
HLGEM
Модульные и интеграционные тесты предназначены для функциональности, а не для производительности, поэтому вы можете тестировать с небольшими объемами данных
user151019
Модульное тестирование никогда не должно использовать базу данных - интеграционные тесты используют базы данных.
Николас Мейн
1
На самом деле вы говорите о нагрузочном тестировании. Если у вас есть набор тестов Acceptence и они подключены к инструменту нагрузочного тестирования, вы сможете добиться желаемого эффекта.
Николас Мейн