Показаны сообщения с ярлыком Юнит тестирование. Показать все сообщения
Показаны сообщения с ярлыком Юнит тестирование. Показать все сообщения

среда, 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 являются вполне осязаемые артефакты, а именно высокое качества дизайна и кода, которое получается за счет коротких итераций разработки и проверки результата.

воскресенье, 8 июня 2014 г.

Is TDD Dead. Часть 5

В то время, как в Виларибо спорят жив ли TDD или мертв, в Вилабаджо думают, а стоит ли компилировать код перед коммитом.

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

Is TDD Dead. Part V on Youtube. В целом, получилось более затянуто чем обычно (ведь выступление длилось в двое дольше), но, как всегда, весьма любопытно.

Проблема обсуждения вопросов дизайна

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

Обсуждение вопросов дизайна является довольно сложным вопросом и у этого есть как минимум несколько причин. Во-первых, дизайн любой системы постоянно развивается, при этом результат зависит не только от способностей членов команды, но и от исторического контекста (злосчастное, «исторически сложилось»). Это значит, что мы не можем судить о существующем дизайне в вакууме, нам нужно еще и понимать, как мы к нему пришли и какие проблемы считали наиболее приоритетными. Во-вторых, не существует достаточно объективной меры качества дизайна, которая бы четко доказывала, что одно решение действительно лучше другого. В-третьих, при обсуждении вопросов дизайна автор статьи или книги сталкивается с вопросом выбора размера и сложности примера. С одной стороны, нет смысла рассматривать продвинутые техники проектирования на примитивных примерах, ведь примитивные задачи можно решить любым способом. С другой стороны, автор не может давать слишком сложные примеры, поскольку 90% читателей просто не захотят тратить свое время и с ними разбираться.

вторник, 13 мая 2014 г.

Модульный тест: определение

В наших с вами интернетах недавно поднялся нешуточный шум по поводу того, жив ли TDD сейчас, нужен ли он, и в каком виде. Все началось со статьи Дэвида Хансона "TDD is dead. Long living testing", после которой последовали статьи многих авторов и живые обсуждения этой проблемы включая hangout вместе с Дэвидом, Кентом Беком и Мартином Фаулером .

Но немногие знают, что за несколько дней до этого все тот же Мартин Фаулер постарался дать определение модульного теста (bliki:UnitTest), перевод которого представлен ниже. А после перевода идут кое-какие мои мысли по этому поводу.

---------------------------------

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

четверг, 10 апреля 2014 г.

Об автоматизированном тестировании

и книге Стива Фримана "Growing Object-Oriented Software Guided by Tests"

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

Содержание

В мире разработки ПО нет более неоднозначной темы, чем тестирование. Нет, я не о тестировании ПО в целом, тут все ясно, оно нужно, без него никак. А вот отношение к автоматическим тестам и особенно к юнит-тестам весьма неоднозначное.

понедельник, 20 января 2014 г.

Microsoft Fakes. Тестирование поведения

DISCLAIMER: исходный код Verification Fakes можно найти на github, а скомпилированная версия доступна через nuget.org/packages/VerificationFakes.

В прошлой заметке мы рассмотрели примеры использования Microsoft Fakes для создания стабов – заглушек, возвращающих требуемые данные. Однако в некоторых случаях нам все же нужно проверить, что в определенных условиях тестируемый класс обращается к некоторой зависимости. Такой вид тестирования называется тестированием поведением и именно такой вид «подделок» каркасом Microsoft Fakes практически не поддерживается.

вторник, 14 января 2014 г.

Microsoft Fakes. Тестирование состояния

Все приведенные примеры можно найти на github.

Microsoft Fakes – это очередной изоляционный фреймворк, который является логическим продолжением экспериментального проекта Microsoft Moles.

Все изоляционные фреймворки делятся на несколько категорий, в зависимости от времени генерации «подделок» и их типу:

По времени генерации:

  • генерация на лету во время исполнения тестов;
  • во время компиляции;

По типу генерируемых «подделок»:

  • на основе полиморфизма, что позволяет «мокать» лишь полиморфные методы;
  • на основе CLR Profiling API, что позволяет мокать невиртуальные методы, включая статические.

понедельник, 13 мая 2013 г.

Пример тестируемого дизайна

В комментариях к предыдущей заметке был задан такой вопрос:

«Вот есть, сккажем, класс, который читает какой-нибудь файл и потом его анализирует. Как такое тестировать?

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

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

среда, 8 мая 2013 г.

Как тестировать закрытые методы?

В комментариях к одной из заметок в Г+ мне предложили рассказать о тестировании закрытых методов. Поскольку это интересная тема, то в сегодня я постараюсь ответить на этот вопрос.

Q: - Как тестировать закрытые методы?
A: - Напрямую – никак!

Ну а теперь давайте поговорим об этом более подробно.

понедельник, 3 сентября 2012 г.

Moq. Примеры использования

DISCLAIMER. Все приведенные здесь примеры можно найти на github.

Moq – это простой и легковесный изоляционный фреймврк (Isolation Framework), который построен на основе анонимных методов и деревьев выражений. Для создания моков он использует кодогенерацию, поэтому позволяет «мокать» интерфейсы, виртуальные методы (и даже защищенные методы) и не позволяет «мокать» невиртуальные и статические методы.

ПРИМЕЧАНИЕ
На рынке существует лишь два фрейморка, позволяющих «мокать» все, что угодно. Это TypeMockIsolator и Microsoft Fakes, доступные в Visual Studio 2012 (ранее известные под названием Microsoft Moles). Эти фреймворки, в отличие от Moq, используют не кодогенерацию, а CLR Profiling API, что позволяет вклиниться практически в любой метод и создать моки/стабы даже для статических, невиртуальных или закрытых методов.

В Moq нет разделения между «стабами» (stubs) и «моками» (mocks) или, более формально, нет разделения на верификацию состояния и верификацию поведения. И хотя в большинстве случаев различия между стабами и моками не так уж и важны, а иногда одна и та же заглушка выполняет обе роли, мы будем рассматривать примеры от простых к сложным, поэтому вначале рассмотрим примеры проверки состояния, а уже потом перейдем к проверке поведения.

вторник, 28 августа 2012 г.

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

DISCLAIMER: все примеры в этой статье написаны с использованием NUnit, однако все их можно применять и с другими тестовыми фреймворками, как xUnit и MbUnit.

Юнит тесты – это отличная штука; они помогают навести порядок в дизайне приложения, являются незаменимым средством при рефакторинге, позволяют делать процесс разработки более управляемым и т.п. Но как и любой другой инструмент юнит тесты тоже можно использовать неправильно. Если с плохо поддерживаемым кодом все мы хоть как-то привыкли бороться, поскольку сталкиваемся с ним постоянно, но когда на каждую строку г#%@&-кода приходится еще пара строк таких же по качеству тестов, то положение становится каким-то совсем уж невеселым.

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

четверг, 28 июня 2012 г.

Контракты vs Юнит тесты

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

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

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

четверг, 5 апреля 2012 г.

Что значат для вас юнит-тесты?

С технической точки зрения юнит-тесты – это очень простой инструмент, основанный на паре несложных концепций: (1) тестируемый класс, (2) набор тестовых методов, завернутых в некоторый класс и (3) набор методов, с помощью которых можно удостовериться в том, что состояние тестового класса соответствует (или не соответствует) некоторому значению.

Это очень простая штуковина, которая может кардинальным образом повлиять на процесс разработки в целом. С одной стороны существует TDD (“test-first approach), при котором тесты «драйвят» не только процессом кодирования, но и процессом проектирования (т.е. дизайном системы). С другой стороны существуют разработчики с противоположной точкой зрения, которые считают юнит-тесты пустой тратой времени, потому что они не приносят никакой ценности пользователю.

среда, 11 января 2012 г.

The Art of Unit Testing

imageЕсть некоторые категории знаний, которые профессиональный разработчик познает в процессе своей работы, не прилагая к этому особенных дополнительных усилий. Вот, например, мало кто из нас читал замечательную книгу по регулярным выражениям Джеффри Фирддла, чтобы познакомиться с одноименной темой. Безусловно, есть масса людей, для которых «регвыры» стали смыслом жизни и без подобных фундаментальных знаний никак не обойтись. Но в большинстве случаев пары мелких статей и справки в соответствующем разделе документации будет достаточно для более или менее комфортной работы с регулярными выражениями (если такое понятие, как «комфортная работа» с регулярными выражениями вообще существуетJ).

Аналогичным образом мы обычно относимся и к изучению юнит тестирования. Ведь юнит-тесты – это же не rocket science; для их изучения не требуется многолетняя подготовка и множество бессонных ночей проведенных за изучением толстенных «талмудов» от гуру юнит-тестирования. Концепцию автоматизированного тестирования кода можно объяснить за 10 минут, а познакомившись с одним из тестовых фреймворков семейства xUnit (еще 15 минут), вы сможете работать с любым другим фреймворком практически сразу же. Затем нужно будет потратить еще 20 минут на изучение какого-нибудь изоляционного фреймворка, типа Rhino Mocks, и, вуаля, у нас есть еще один профессионал в области юнит-тестов.

понедельник, 19 декабря 2011 г.

Стабы и моки

Существует категория классов, которые тестировать весьма просто. Если класс зависит только от примитивных типов данных и не имеет никаких связей с другими бизнес-сущностями, то достаточно создать экземпляр этого класса, «пнуть» его некоторым образом путем изменения свойства или вызова метода и проверить ожидаемое состояние.

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

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

понедельник, 14 марта 2011 г.

Частичные классы

Частичные классы (partial classes) (*) – это весьма простая конструкция языка C#, которая позволяет определить один класс в нескольких файлах (**). Это далеко не rocket science, но существует пара интересных сценариев их применения, которые являются не столь очевидными с первого взгляда. Но об этом позже, а начнем мы лучше с простого объяснения, что это такое и с чем его едят.

Общие сведения

Давайте вспомним старые добрые дни C# 1.0, когда спецификация языка была вдвое тоньше, возможностей языка было на порядок меньше, да и не было никаких LINQ-ов и всех остальных dynamic-ов (и вопросов на собеседовании, соответственно, тоже). Но даже тогда компилятор языка старался скрасить наши с вами серые будни и усердно выполнял всякую унылую работу, но делал он это не втихаря, путем генерации всяких там анонимных классов или методов, а путем генерации C# кода с помощь дизайнеров. И все бы ничего, но с этим подходом зачастую приходили и некоторые проблемы, которые, в основном сводились к ярому желанию разработчика расширить этот код и к ярому сопротивлению этого кода от подобного ручного вмешательства. Другими словами, внесение любых изменений в автосгенерированный код всегда вели к беде, ибо тут же прибивались компилятором при повторной генерации.

понедельник, 13 декабря 2010 г.

Microsoft Moles

Moles – это легковесный тул от MS Research, который умеет автоматически генерировать заглушки для интерфейсов и виртуальных методов, а также для sealed классов, невиртуальных и статических методов (!), путем генерации кода, которому позднее можно будет подсунуть нужный делегат, вызываемый вместо определенного метода. Первый тип заглушек называется стабы (stubs), а второй – молы (moles). Именно эту штуку я использовал для тестирования асинхронных операций, о которых я рассказывал ранее, но давайте обо всем по порядку.

Stubs

Давайте рассмотрим такой пример. Предположим, что мы понимаем ценность модульных тестов, а также таких принципов, как Dependency Inversion, и других безумно полезных принципов и паттернов (может быть всех остальных принципов S.O.L.I.D., а возможно даже и F.I.R.S.T.). И дело даже не в том, что мы фанаты тестов или дядюшки Боба, а просто потому, что мы знаем, что высокая связность – это плохо. Поэтому мы стараемся в разумных пределах уменьшить зависимости путем выделения интерфейсов с последующим «инжектом» их в конструкторы классов или в методы, которым эти интерфейсы необходимы для выполнения своих задач.

четверг, 3 июня 2010 г.

Пять принципов чистых тестов (F.I.R.S.T. Principles)

Многим разработчикам известны принципы проектирования, которые благодаря Роберту Мартину получили звучное название  S.O.L.I.D. Многим из этих принципов уже не один десяток лет (принцип подстановки Лисков впервые был озвучен более двадцати лет назад), они были опробованы на миллионах строк кода, тысячами разработчиками (при этом добрая половина из них применяла эти принципы даже не имея понятия об этом:) ). Конечно, слепое следование любым принципам никогда ни к чему хорошему не приводило и приводить не будет, но тем не менее в них описаны разумные вещи, о которых нужно как минимум знать, да и понимать их тоже будет совсем не лишним.

Помимо принципов проектирования существуют и другие, незаслуженно менее известные принципы, которые положены в основу написания качественных тестов. На каждом шагу говорится о качестве кода, продуманности дизайна или архитектуры, но при этом довольно слабо уделяется внимание читабельности и сопровождаемости тестов. А ведь объем кода в тестах по хорошему может быть (а точнее должен быть) не меньшим, чем объем кода; возможно именно из-за некачественного кода модульных тестов они так редко поддерживаются в актуальном состоянии, что очень быстро приводит к тому, что они устаревают, становятся неактуальными и вообще остаются на “обочине” процесса разработки.

Принципы написания качественных тестов придуманы не на пустом месте. Большинство опытных разработчиках знают о них точно так же, как и о принципах проектирования без помощи “Дядюшки” Боба, но как и в случае с принципами проектирования именно Боб Мартин объединил пять принципов тестирования, в результате чего получилось звучное название Б.Н.П.О.С. (или F.I.R.S.T., если вам звучность русскоязычного названия не по душе): Fast (Быстрота), Independent (Независимость), Repeatable (Повторяемость), Self-Validating (Очевидность) (*), Timely (Своевременность)).

Итак, каждый модульный тест должен обладать следующими характеристиками:

Быстрота (Fast). Тесты должны выполняться быстро. Все мы знаем, что разработчики люди, а люди ленивы, поскольку эти выражения являются “транзитивными”, то можно сделать вывод, что люди тоже ленивы. А ленивый человек не захочет запускать тесты при каждом изменении кода, если они будут долго выполняться.

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

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

Очевидность (Self-Validating). Результатом выполнения теста должно быть булево значение. Тест либо прошел, либо не прошел и это должно быть легко понятно любому разработчику.  Не нужно заставлять людей читать логи только для того, чтобы определить прошел тест успешно или нет.

Своевременность (Timely). Тесты должны создаваться своевременно. Несвоевременность написания тестов является главной причиной того, что они откладываются на потом, а это “потом” так никогда и не наступает. Даже если вы и не будете писать тесты перед кодом (хотя этот вариант уже доказал свою жизнеспособность) их нужно писать как минимум параллельно с кодом.

-----------------------------------

(*) Пять этих принципов опубликованы в книге “Clean Code”, поэтому русскоязычный вариант перевода взят из русскоязычного издания этой книги. Можно долго спорить о корректности перевода Self-Validating, как “Очевидность”, но, как говорится, что написано пером… И хотя вариант типа “Самодостоверность” выглядит более корректным, с точки зрения семантики вариант “Очевидность” кажется не таким уж и плохим.