среда, 4 мая 2016 г.

Параметризованные юнит-тесты в xUnit

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

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

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

вторник, 26 апреля 2016 г.

Что мне не нравится в Xunit

xUnit - это самый популярный нынче тестовый фреймворк, который сейчас активно используется во многих open source проектах типа Roslyn, CoreFx и сотнях проектах поменьше. Я всю свою сознательную жизнь использовал NUnit, но сейчас, иногда по работе, иногда просто при работе с чужеродными кодовыми базами, мне приходится иметь дело с xUnit.

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

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

Итак, начнем.

понедельник, 18 апреля 2016 г.

Размышления о TDD

В наших с вами тырнетах снова образовался всплеск активности по поводу TDD, о его здоровье и жизненных показателях. Началось все с поста Ian Sommerville “Giving up on test-first development”, а продолжилось постом Боба «я все знаю о дизайне» Мартине “Giving up on TDD” и еще несколькими постами.

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

Результат vs. Процесс

Когда речь заходит о TDD (Test-Driven Development), то возникает впечатление, что речь идет о каком-то тайном знании. «Знающие» индивидуумы рассказывают о своих успехах с хитрым выражением лица и некоторым снисхождением к тем, кто еще не осознал всей прелести этой аббревиатуры. При этом, когда их просят рассказать о выгодах сего процесса, они начинают бормотать о пользе тестов, важности хорошего дизайна, легкости рефакторинга и гибкости получаемых систем. Иногда, в качестве аргументом могут встречаться фразы о самодокументируемом коде, наличиях «встроенной» в тесты спецификации и высоком покрытии, как о важном артефакте любой вменяемой кодовой базы. А если вы начнете детально обсуждать модульные тесты, то вас перебьют и скажут, что TDD – это вообще-то про дизайн (т.е. про проектирование), а не про тестирование.

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

вторник, 12 апреля 2016 г.

ErrorProne.NET. Часть 4. Реализуем Extract Method

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

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

clip_image002

Каждый фиксер должен указать, какую проблему он должен решать. Для этого нужно унаследоваться от класса CodeFixProvider и переопределить свойство FixableDiagnosticIds:

пятница, 11 марта 2016 г.

ErrorProne.NET. Часть 3

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

В языке C# есть довольно много возможностей, которые выворачиваются в довольно сложный IL-код и приводят к поведению, не всегда очевидному для пользователей/читателей кода. Хорошим примером подобного рода является ограничение new() в обобщениях, использование которой приводит к использованию отражения (reflection) и созданию новых экземпляров объектов с помощью Activator.CreateInstance, что меняет «профиль» исключений и негативно сказывается на производительности.

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

вторник, 8 марта 2016 г.

ErrorProne.NET. Часть 2

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

ErrorProne.NET унаследовал многие возможности из моего другого проекта – ExceptionAnalyzer, но в несколько измененном виде. Вот какие правила он содержит:

  • ERP021 – Incorrect exception propagation: «неправильный» проброс исключения с помощью throw ex; вместо throw;
  • ERP022 – Unobserved exception in generic exception handler: когда блок catch, который перехватывает все исключения возвращает управления без попытки «наблюдения» перехваченного исключения.
  • ERP023 – Suspicious exception handling: only Message property was observed: когда в обобщенном блоке catch идет обращение лишь к свойству ex.Message исключения.

Теперь обо всех этих исключениях более подробно.

четверг, 25 февраля 2016 г.

ErrorProne.NET. Часть 1

У меня уже давно чесались руки сделать анализатор, который поможет отлавливать разные ошибки, в той или иной степени, специфичные для платформы .NET. Многие подобные ошибки уже прекрасно отлавливает R#, но ведь всегда хочется чего-то своего. К тому же, анализаторы Розлина бесшовно интегрируются в билд процесс, могут использоваться по ночам (*), да и могут содержать рулы, специфичные для вашего продукта.

Итак, взяв за основу идеи из R# и из аналогичной библиотеки для Java от гугла под названием Error Prone, я взялся за работу. Ниже представлен первая часть результатов моей работы.

Вызов чистых методов

Отсутствие «наблюдение» результатов вызова чистого метода является одной из наиболее частых ошибок, которые возникают во время локального тестирования. Проблема в том, что просто читая код, очень сложно сказать заранее, является ли вызов someCollection.Union(anotherCollection) «чистым» и возвращает новую коллекцию, или же меняет исходную.