Устанавливать/отрывать поврежденную работоспособность теста?

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

Принцип DRY, по-видимому, является нашим оружием по выбору для боевого обслуживания проблемы, но как насчет обслуживания тестового кода? Выполните те же самые правила применять?

Несколько сильных голосов в сообществе разработчиков тестирования считают, что установка и отключение вредны и их следует избегать... чтобы назвать несколько:

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

Каков был ваш опыт? Устранение сбоев в установке/отключении или помощь в тестировании?

UPDATE: делать более мелкозернистые конструкции, подобные тем, которые доступны в JUnit4 или TestNG (@BeforeClass, @BeforeGroups и т.д.), имеют значение?

Ответы

Ответ 1

Большинство (если не все) типов допустимых для методов настройки и удаления могут быть записаны как методы factory, которые позволяют DRY, не попадая в проблемы, которые, по-видимому, страдают от установки/парадигма срыва.

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

Однако при настройке, кажется, есть несколько причин, по которым вам нужно делать что-то до того, как тест действительно будет запущен. Например, построение состояния объекта для подготовки к тестированию (например, создание структуры зависимостей для зависимостей). Это действительная причина для настройки, но так же легко можно сделать с помощью factory.

Кроме того, существует различие между установкой/отключением уровня класса и метода. Это нужно иметь в виду при рассмотрении того, что вы пытаетесь сделать.

Моя самая большая проблема, с которой я столкнулась с использованием парадигмы установки/разрыва, заключается в том, что мои тесты не всегда соответствуют одному и тому же шаблону. Это привело меня к использованию шаблонов factory вместо этого, что позволяет мне иметь СУХОЙ, а в то же время быть читаемым и совсем не смущать других разработчиков. Идя по маршруту factory, я смог получить торт и съесть его.

Ответ 2

Они действительно помогли с нашей проверкой ремонтопригодности. Наши "единичные" тесты - это на самом деле полные сквозные интеграционные тесты, которые записываются в БД и проверяют результаты. Не моя вина, они были такими, когда я пришел сюда, и я работаю над тем, чтобы что-то изменить.

В любом случае, если один тест не прошел, он перешел к следующему, пытаясь ввести одного и того же пользователя из первого теста в БД, нарушив ограничение уникальности, и отказы просто каскадировались оттуда. Перенос создания/удаления пользователя в методах [Fixture] [SetUp | TearDown] позволил нам увидеть один пробой, который провалился, без всякого движения, и сделал мою жизнь намного проще и менее прочной.

Ответ 3

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

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

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

Ответ 4

Я согласен со всем, что должен сказать Джозеф, особенно в отношении tearDown, являющегося признаком написания интеграционных тестов (и в 99% случаев это то, для чего я его использовал), но в дополнение к тому, что я сказал бы что использование установки является хорошим индикатором того, когда тесты должны быть логически сгруппированы вместе и когда их следует разбить на несколько тестовых классов.

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

Следуя примерам в "Test Driven" , метод настройки возникает из-за удаления дублирования в тестовых случаях.

Ответ 5

Я использую установку довольно часто в Java и Python, часто для создания коллаборационистов (реальных или тестовых, зависимых). Если тестируемый объект не имеет конструкторов или только соавторов в качестве конструкторов, я создам объект. Для простого класса значений я обычно не беспокоюсь о них.

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

Интеграционные тесты и функциональные тесты (которые часто используют инфраструктуру xunit), скорее всего, потребуют установки и удаления.

Важно помнить, что светильники не только DRY.

Ответ 6

У меня нет проблем с методами тестирования и разрывом как таковыми.

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

xUnit.Net избавляется от установки/отрыва, потому что он создает новый объект для каждого запускаемого теста. По существу, конструктор становится методом установки, а финализатор становится методом разрыва. Нет состояния (уровня объекта) между испытаниями, устраняя этот потенциальный вектор ошибки.

Большинство тестов, которые я пишу, имеют некоторую настройку, даже если это просто создает нужные мне mocks и подключает тестируемый объект до макетов. То, что они не делают, - это разделять какое-либо состояние между тестами. Teardown просто следит за тем, чтобы я не разделял это состояние.

Ответ 7

У меня не было времени прочитать оба из того, что вы разместили, но мне особенно понравился этот комментарий:

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

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

Ответ 8

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

  • Тестовый код по своей природе является процедурным. В общем случае установка/отключение do имеют тенденцию уменьшать читаемость/фокусировку теста.
  • Методы настройки имеют тенденцию инициализировать больше, чем требуется для любого отдельного теста. При злоупотреблении они могут стать громоздкими. Мастера объектов, сборщики тестовых данных, возможно, такие рамки, как FactoryGirl, выглядят лучше при инициализации тестовых данных.
  • Они поощряют "раздувание контекста" - чем больше тестовый контекст становится, тем менее удобным он будет.

В той степени, в которой моя установка/срыв не делает этого, я думаю, что их использование оправдано. В тестах всегда будет некоторое дублирование. Нил Форд заявляет об этом как "Тесты могут быть мокрыми, но не вымачивать..." Кроме того, я думаю, что их использование более оправдано, когда мы говорим не об отдельных тестах, а в тестах интеграции более широко.

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

Мне бы хотелось услышать, как другие об этом относятся.

Ответ 9

Если вам нужна настройка и срыв, чтобы ваши модульные тесты работали, возможно, вам действительно нужны макетные объекты?