Правильный подход для модульного тестирования сложных взаимодействий - PullRequest
4 голосов
/ 02 ноября 2009

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

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

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

AddObject1SuccessTest
AddObject2WithSameUniqueCodeTest
(полагается, что первый тест сначала создал object1, а затем ожидает сбой)
AddObject2SuccessTest
UpdateObject2WithSameUniqueCodeTest
(полагается на первый тест, создавший object1, и на третий тест, создавший object2, а затем ожидает сбой)
UpdateObject2SuccessTest
GetObjectListTest
DeleteObjectsTest
(с использованием добавленных идентификаторов)

Однако между тестами нет состояния и нет очевидного способа передачи, скажем, добавленных идентификаторов в deletetest, например.

Итак, верно ли то, что правильный подход для модульного тестирования сложных взаимодействий является сценарием?

Например

AddObjectSuccessTest
(который создает объект, проверяет данные и затем удаляет их)
AddObjectWithSameUniqueCodeTest
(который создает объект 1, затем пытается создать объект 2 с ошибкой, а затем удаляет объект 1)
UpdateObjectWithSameUniqueCodeTest
(который создает объект 1, затем создает объект 2 и затем пытается обновить объект 2, чтобы тот же уникальный код, что и у объекта 1, с ошибкой, а затем удаляет объект 1 и объект 2)

Я ошибаюсь?

Спасибо

Ответы [ 2 ]

5 голосов
/ 02 ноября 2009

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

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

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

Такое состояние предварительного условия называется Fixture. Книга xUnit Test Patterns содержит много информации и рекомендаций по управлению приборами в различных сценариях.

3 голосов
/ 03 ноября 2009

В дополнение к тому, что сказал Марк, да, каждый тест должен быть полностью независимым от других, и, если использовать ваши термины, каждый тест должен быть автономным сценарием, который может выполняться независимо от других.
Из того, что вы описываете, я предполагаю, что вы тестируете персистентность, потому что на ваших шагах есть удаление сущностей, созданных вами в конце теста, чтобы очистить состояние. В идеале, модульное тестирование выполняется полностью в памяти без разделения состояния между каждым тестом. Один из способов добиться этого - использовать Mocks. Я предполагаю, что у вас есть что-то вроде хранилища, так что ваш класс вызывает Repository.Add (myNewObject), который вызывает что-то вроде Repository.ValidateObjectCanBeAdded (myNewObject). Вместо того, чтобы тестировать реальный репозиторий, который будет добавлять объекты в базу данных и требовать их удаления для очистки состояния после теста, вы можете создать интерфейс IRepository, используя два одинаковых метода, и использовать Mock для проверки этого, когда ваш Класс вызывает IRepository, он использует правильные методы с правильными аргументами в правильном порядке. Это также дает вам возможность установить «поддельное» хранилище в любое нужное вам состояние в памяти без необходимости физического добавления или удаления записей из реального хранилища.
Надеюсь, это поможет!

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