Я тест-драйв метод, который заключается в создании коллекции объектов данных. Я хочу убедиться, что свойства объектов установлены правильно. Некоторые свойства будут установлены одинаково; другим будет присвоено значение, которое зависит от их положения в коллекции. Естественный способ сделать это, кажется, с петлей. Однако Рой Ошеров настоятельно рекомендует не использовать логику в модульных тестах ( Art of Unit Testing , 178). Он говорит:
Тест, содержащий логику, обычно тестирует более чем одну вещь за раз, что не рекомендуется, потому что тест менее читабелен и более хрупок. Но тестовая логика также добавляет сложности, которая может содержать скрытую ошибку.
Как правило, тесты должны представлять собой серию вызовов методов без потоков управления, даже
try-catch
без вызовов assert.
Тем не менее, я не вижу ничего плохого в своем дизайне (как еще вы генерируете список объектов данных, некоторые значения которых зависят от того, где в последовательности они находятся? - не могу точно сгенерировать и протестировать их отдельно). Что-то не подходит для тестирования с моим дизайном? Или я слишком жестко предан учению Ошерова? Или есть какая-то секретная магия юнит-теста, о которой я не знаю, которая обходит эту проблему? (Я пишу в C # / VS2010 / NUnit, но, если возможно, ищу не зависящие от языка ответы.)
источник
in
) необходимым, если тест «Frob был успешно добавлен в существующую коллекцию».toString()
коллекционирую и сравниваю с тем, что должно быть. Просто и работает.Ответы:
TL; DR:
Первое, что нужно проверить - догма бесполезна. Я с удовольствием читаю «Путь Фестиваля», в котором легко и искренне говорится о некоторых проблемах с догмой.
Если тест нужно написать каким-то образом, запишите его так. Попытка заставить тест в некоторой идеализированной структуре теста или не иметь вообще ничего не является хорошей вещью. Сегодняшнее тестирование лучше, чем «идеальное» тестирование в более поздний день.
Я также укажу на немного уродливого теста:
Это может считаться трюизмом для тех, кто следил за ним долгое время ... и они просто укоренились в мышлении и написании тестов. Для людей, которые не были и пытаются достичь этой точки, напоминания могут быть полезны (я даже нахожу, что их перечитывание помогает мне не попасться в какую-то догму).
Учтите, что при написании некрасивого теста, если код, это может быть признаком того, что код слишком много пытается сделать. Если код, который вы тестируете, слишком сложен, чтобы его можно было правильно выполнить путем написания простого теста, вы можете рассмотреть возможность разбить код на более мелкие части, которые можно протестировать с помощью более простых тестов. Не следует писать модульный тест, который делает все (тогда это может быть не модульный тест). Подобно тому, как «объекты бога» плохи, «тесты бога» тоже плохи и должны служить указанием вернуться назад и снова посмотреть на код.
Вы должны быть в состоянии выполнить весь код с разумным охватом с помощью таких простых тестов. Тесты, которые выполняют больше сквозных тестов, которые имеют дело с более крупными вопросами («У меня есть этот объект, упорядоченный в xml, отправленный в веб-сервис, через правила, откат назад и демаршаллирование») - отличный тест, но он, безусловно, не не является модульным тестом (и попадает в сферу интеграционного тестирования - даже если у него есть поддельные сервисы, которые он вызывает, и пользовательские базы данных памяти для тестирования). Он все еще может использовать платформу XUnit для тестирования, но каркас тестирования не делает его модульным тестом.
источник
Я добавляю новый ответ, потому что моя точка зрения отличается от того, когда я писал оригинальный вопрос и ответ; не имеет смысла объединять их в одно целое.
Я сказал в оригинальном вопросе
Вот где я ошибся. Проработав функциональное программирование за последний год, я теперь понимаю, что мне просто нужна была операция сбора с аккумулятором. Тогда я мог бы написать свою функцию как чистую функцию, которая работала бы над одной вещью, и использовать некоторую стандартную библиотечную функцию, чтобы применить ее к коллекции.
Итак, мой новый ответ: используйте методы функционального программирования , и вы будете избегать этой проблемы большую часть времени. Вы можете написать свои функции для работы с отдельными вещами и применять их только к коллекциям вещей в последний момент. Но если они чисты, вы можете проверить их без ссылки на коллекции.
Для более сложной логики используйте тесты на основе свойств . Когда у них действительно есть логика, она должна быть меньше и обратно по отношению к логике тестируемого кода, и каждый тест проверяет намного больше, чем модульный тест на основе регистра, что небольшой объем логики того стоит.
Прежде всего всегда опирайтесь на ваши типы . Получите самые сильные типы, которые вы можете, и используйте их в своих интересах. Это уменьшит количество тестов, которые вы должны написать в первую очередь.
источник
Не пытайтесь проверять слишком много вещей одновременно. Каждое из свойств каждого объекта данных в коллекции слишком много для одного теста. Вместо этого я рекомендую:
Делая это таким образом, вы делаете тесты достаточно маленькими, чтобы пропустить циклы не было болезненным. C # / Пример блока, данный тестируемый метод
ICollection<Foo> generateFoos(uint numberOfFoos)
:Если вы привыкли к парадигме «тест плоского модуля» (без вложенных структур / логики), эти тесты кажутся довольно чистыми. Таким образом, логику избегают в тестах, идентифицируя исходную проблему как попытку проверить слишком много свойств одновременно, а не отсутствие циклов.
источник