Как вы unit test бизнес-приложения?

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

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

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

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

Любые мысли, идеи, предложения или советы оценены.

Ответы

Ответ 1

Я должен повторить комментарий @Phil Bennett, когда я пытаюсь подойти к этим интеграционным тестам с откатом решения.

У меня есть очень подробное сообщение об интеграции, проверяющем ваш уровень доступа к данным здесь

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

О единичном тестировании бизнес-логики внутри вашего приложения я бы также закрепил комментарии @Phil и @Mark, потому что если вы издеваетесь над всеми зависимостями, которые имеет ваш бизнес-объект, становится очень просто протестировать вашу логику приложения на одном объекте время;)

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

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

  • 2 - Интеграция проверяет логику, которая возникает, когда вы берете   управляемые данные (из предыдущего   метод, который мы тестировали) и назовем   соответствующую хранимую процедуру. Делать   это внутри тестирования, специфичного для данных   класс, чтобы вы могли откат после его   завершено. После сохранения   процедура выполнилась, выполните запрос   против базы данных, чтобы получить   теперь, когда мы сделали некоторые   логику против данных и проверить ее   имеет значения, которые вы ожидали   (логика после хранимой процедуры /etc )

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

Ответ 2

Мои автоматические функциональные тесты обычно следуют одному из двух шаблонов:

  • Подключенные к базе данных тесты
  • Мок-тесты уровня устойчивости

Подключенные к базе данных тесты

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

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

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

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

Мок-тест на сохранение уровня

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

Хорошая вещь об использовании тестов макетных объектов заключается в том, что вы можете получить очень конкретную информацию. Часто случаются пути выполнения, которые вы просто не можете достичь в автоматических тестах без макетных объектов. Они также освобождают вас от поддержки большого монолитного набора тестовых данных.

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

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

Ответ 3

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

Даже тогда я склонен открывать транзакцию БД в методе TestFixtureSetUp (очевидно, это зависит от того, какую инфраструктуру модульного тестирования вы можете использовать) и откат транзакции в конце тестового набора TestFixtureTeardown.

Ответ 4

Mocking Frameworks позволяет тестировать бизнес-объекты. Тесты с управлением данными часто заканчиваются тем, что становятся более сложными, чем unit test, они также несут в себе бремя управления состоянием хранилища данных до и после выполнения теста и времени, затраченного на соединение и выполнение запросов.

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

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

Ответ 5

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

В целом все правила стандартного тестирования до сих пор сохраняются:

  • Постарайтесь, чтобы устройства были протестированы как можно более компактными и дискретными.
  • Попробуйте сделать тесты независимыми.
  • Код фактора для развязки зависимостей.
  • Используйте mocks и stub для замены зависимостей (например, dataaccess)

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

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

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

Ответ 6

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