Как писать юнит-тесты. Рабочие примеры и подробное руководство
Поэтому к написанию unit-тестов нужно подойти со всей ответственностью.
Вы делаете презентационный софт для выставки и очень сильно ограничены во времени.
Вы создаете идеальный код и всегда вообще без ошибок. А сам код может мгновенно изменяться под требования заказчика, и более того, код способен объяснить заказчику, что его требования — это полная нелепость и непонимание сути заказываемой разработки.
Тест должен быть достоверным.
Он не должен зависеть от окружения.
Написанный тест должен легко обслуживаться.
Тест должен быть максимально простым и понятным.
Должен присутствовать автоматический режим запуска тестов.
Тест пишется для того кода, в котором нет уверенности.
У любого теста должна быть возможна фальсификация, то есть должно быть такое входное значение, чтобы тест провалился.
Правильно выбирать логическое размещение unit-тестов в вашей VCS. К примеру, если ваша разработка монолитная, то тесты расположить в папку Tests. Если приложение состоит из нескольких элементов, то имеет смысл хранить тесты в папке каждого элемента.
При тестировании классов использовать такой же способ называть тест. Должен быть такой же подход, как описано выше, например: когда у вас есть класс FindProblem, то его тестовый проект должен быть FindProblemTests.
Выбирать фреймворк для теста, который лучше всего подойдет. Не нужно изобретать колесо, когда уже придумали велосипед. Можно воспользоваться некоторыми популярными фреймворками для теста: MsTest, NUnit, xUnit и др.
Писать тело тест а в едином стиле, чтобы было проще читать и поддерживать код.
Тестировать одну вещь за раз. Нужно упрощать процесс тестирования. Если вам нужно протестировать сложный процесс (например, процесс покупки в интернет-магазине), то разбивайте его на более мелкие части и тестируйте их отдельно.
Не относиться к юнит-тестам как к второстепенному коду. Все принципы и технологии при разработке основного кода должны использоваться и при написании тестов.
«The Art of Unit Testing» от Roy Osherove;
«xUnit Test Patterns: Refactoring Test Code» от Gerard Meszaros;
«Working Effectively with Legacy Code» от Michael Feathers;
«Pragmatic Unit Testing in C# with NUnit, 2nd Edition» от Andy Hunt и Dave Thomas.
Заключение
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Пишем unit тесты так, чтобы не было мучительно больно
Любую задачу в программировании можно выполнить массой разных способов, и не все они одинаково полезны. Хочу рассказать о том, как можно накосячить при написании модульных тестов. Я пишу мобильные приложения уже 6 лет, и в моем «багаже» много разных кейсов. Уверен, что кому-то будет полезно.
Перед тем, как разобрать плохие практики, кратко пробежимся по свойствам и качествам хорошо написанных тестов.
Хорошо написанные тесты должны быть достоверными и удобными. Как этого добиться.
Тесты должны давать одинаковые результаты независимо от среды выполнения. Где бы ни был запущен тест – на локальной машине под Windows или macOS, или на CI сервере – он должен давать одинаковый результат и не зависеть от времени суток или погоды на Марсе. Единственное, что должно влиять на результат работы теста – тот код, который непосредственно проверяется в нем.
Тесты не должны зависеть друг от друга. Иначе проблема в одном тесте может приводить к каскадной поломке других (да еще и не всегда воспроизводящейся).
Тот случай, когда Капитан был бы доволен. Итак, это применимо к отдельным тестам: чем проще они читаются, тем лучше.
Но также важно, чтобы и результаты выполнения комплекта тестов были не менее очевидны. После прогона тестов должно быть предельно ясно, где именно допущена ошибка. Иными словами, хорошо написанные тесты максимально сужают область поиска ошибок.
Тесты должны прогоняться как можно чаще, а значит, чем быстрее они выполняются, тем они удобней в повседневной работе.
Тесты должны быть написаны одновременно с тестируемым кодом или раньше него.
Также эти качества известны по книгам дядюшки Боба как 5 принципов чистых тестов.
А теперь разберем плохие практики, которые я чаще всего встречал в реальных проектах.
Плохие практики
Берем хорошие практики и делаем все наоборот. А теперь об этом подробнее.
Множество проверок в одном тесте
Несколько проверок в тесте, даже если они связаны по смыслу, вредны. Из-за этого снижается очевидность и ценность результата прогона тестов.
Любая проверка в тесте приводит к его падению. Несколько проверок мешают понять, что конкретно сломалось.
Каждая новая проверка – причина для изменения теста. А значит, меняться такие тесты будут чаще, чем нужно.
Кроме того, современные тестовые фреймворки устроены так, что выбрасывают служебное исключение в случае, если проверка не проходит.
А значит, что все дополнительные проверки после первой сработавшей никогда не выполнятся, и результаты их будут неизвестны.
В общем, проверок должно быть сильно меньше, чем повторений слова «проверка» в этом коротком тексте.
Пример теста с множеством проверок
Что делать? Такие тесты необходимо делить на более мелкие, содержащие одну действительно необходимую проверку.
Пример разделения теста
Почти из всех правил бывают исключения. Поэтому в некоторых случаях несколько проверок допустимы. Например, когда результаты каждой следующей проверки – бессмысленны, если не выполнится предыдущая.
Добавлю простое эмпирическое правило: «Если не понятно, надо ли разделить тест, или можно оставить несколько проверок – надо делить».
Скрытый вызов теста
Выглядит как приватный метод, который содержит проверки и вызывается в других тестах. Частный случай множественных проверок в тесте, и проблемы приносит абсолютно те же.
Пример скрытого вызова теста
Что делать? Способы борьбы аналогичны: делим один тест на несколько.
Тест, который ничего не проверяет
Обратный случай: тест вроде бы содержит проверки, но фактически они будут выполнены всегда. В приведенном примере тест проверяет, как реализовано mockito, а не юзкейс, для которого он написан.
Пример теста, который ничего не проверяет
Что делать? В таких случаях нужно переписать тест, чтобы он проверял поведение тестируемого класса. Или же просто удалить бесполезный тест.
Логика в тестах
Использование логики в тестах – зло. Любой логический оператор, будь то if, when, if not null, циклы и try, увеличивает вероятность ошибки. А ошибки тестов — это последнее, с чем хотелось бы разбираться. Также логика в тесте говорит о том, что в нем, скорее всего, происходит более одной проверки за раз. Страдает читаемость. Сложнее понять, как устроен тестовый метод.
Пример теста с логикой
Что делать? Разделить тест на несколько отдельных, более простых. Логические операторы удалить.
Пример разделения теста с логикой на несколько
Тестирование реализации, а не контракта (избыточное специфицирование)
Контракт класса – это совокупность его открытых методов и полей и договоренности о том, как они работают.
Типичный контракт презентера: при вызове onViewAttach происходит запрос данных, и как только они получены, view должна их отобразить, а в случае ошибки – показать диалог.
Проблема заключается в том, что тест высказывает предположения о внутреннем устройстве тестируемого класса, а не просто проверяет правильность конечного результата в соответствии с контрактом.
В худшем случае происходит всё так: берётся исходник тестируемого класса и переписывается в тест с заменой вызовов зависимостей на проверки.
Перед написанием теста нужно четко сформулировать, что именно проверяется. Проверка должна быть как можно конкретней и при этом не делать предположений о реализации класса.
Пример теста с избыточными проверками
Что делать? Зависит от конкретного случая: где-то нужно просто удалить избыточные проверки, а где-то – разделить тест на несколько более простых.
verifyNoMoreInteractions после каждого теста (в tearDown())
Вызов verifyNoMoreInteractions для всех зависимостей класса после каждого теста несет целый ворох проблем.
В целостный тест добавляется вторая проверка, а значит, снижается ценность результатов каждого теста. Так как уже непонятно, действительно ли что-то сломалось или изменилось количество взаимодействий с зависимостями.
Эта проверка затронет все тесты, в том числе ненаписанные.
В большинстве случаев это неоправданные проверки, которые проверяют реализацию класса под тестом, а не его контракт.
Испортилась читаемость, так как для понимания, что проверяется в тесте, приходится заглядывать еще и в tearDown
Но иногда проверить, не были ли вызваны лишний раз ресурсозатратные методы зависимостей, нужно. Делать это стоит в рамках отдельного теста.
А проверки, что у зависимостей вызван только один метод и ничего более, в тестах можно осуществлять с помощью VerificationMode only().
Разделяемое состояние
Проблема заключается в том, что несколько тестов пользуются одной и той же переменной в памяти, не возвращая ее в исходное состояние. Таким образом, они начинают неявно зависеть друг от друга, что ведет к неочевидным ошибкам и нестабильности тестов. От большей части проблем с разделяемым состоянием спасает тот факт, что JUnit запускает каждый новый тестовый метод в отдельном экземпляре тестового класса. Таким образом, все поля тест-класса инициализируются заново.
Синтетический пример нестабильности тестов из-за разделяемого состояния
Мы посмотрели самые популярные проблемы, которые встречались мне в реальных проектах. Каждая из них усложняет тесты, делая их менее полезными и более дорогими в поддержке. Так же для каждой такой проблемы приведены пути и способы ее решения. Делитесь своими популярными проблемами и эффективными способами их решения.
Из всего перечисленного можно сделать вывод: не все unit тесты одинаково полезны.
Unit-тесты, пытаемся писать правильно, чтобы потом не было мучительно больно
100 модульных тестов и приходится тратить продолжительное время на то чтобы заставить их работать вновь. Итак, приступим к «хорошим рекомендациям» при написании автоматических модульных тестов. Нет, я не буду капитаном очевидностью, в очередной раз описывая популярный стиль написания тестов под названием AAA (Arange-Act-Assert). Зато попытаюсь объяснить, чем отличается Mock от Stub-а и что далеко не все тестовые объекты — «моки».
Глобально модульные тесты можно условно поделить на две группы: тесты состояния (state based) и тесты взаимодействия (interaction tests).
Тесты состояния — тесты, проверяющие что вызываемый метод объекта отработал корректно, проверяя состояние тестируемого объекта после вызова метода.
Тесты взаимодействия — это тесты, в которых тестируемый объект производит манипуляции с другими объектами. Применяются, когда требуется удостовериться, что тестируемый объект корректно взаимодействует с другими объектами.
Стоит также заметить, что модульный (unit) тест может запросто превратиться в интеграционный тест, если при тестировании используется реальное окружение(внешние зависимости) — такие как база данных, файловая система и т.д.
Интеграционные тесты — это тесты, проверяющие работоспособность двух или более модулей системы, но в совокупности — то есть нескольких объектов как единого блока.
В тестах взаимодействия же тестируется конкретный, определенный объект и то, как именно он взаимодействует с внешними зависимостями.
Внешняя зависимость — это объект, с которым взаимодействует код и над которым нет прямого контроля. Для ликвидации внешних зависимостей в модульных тестах используются тестовые объекты, например такие как stubs (заглушки).
Стоит заметить что существует классический труд по модульным тестам за авторством Жерарда Месароша под названием «xUnit test patterns: refactoring test code«, в котором автор вводит аж 5 видов тестовых объектов, которые могут запросто запутать неподготовленного человека:
— dummy object, который обычно передается в тестируемый класс в качестве параметра, но не имеет поведения, с ним ничего не происходит, никакие методы не вызываются. Примером таких dummy-объектов являются new object(), null, «Ignored String» и т.д.
— test stub (заглушка), используется для получения данных из внешней зависимости, подменяя её. При этом игнорирует все данные, могущие поступать из тестируемого объекта в stub. Один из самых популярных видов тестовых объектов. Тестируемый объект использует чтение из конфигурационного файла? Передаем ему ConfigFileStub возвращающий тестовые строки конфигурации для избавления зависимости на файловую систему.
— test spy (тестовый шпион), используется для тестов взаимодействия, основной функцией является запись данных и вызовов, поступающих из тестируемого объекта для последующей проверки корректности вызова зависимого объекта. Позволяет проверить логику именно нашего тестируемого объекта, без проверок зависимых объектов.
— mock object (мок-объект), очень похож на тестовый шпион, однако не записывает последовательность вызовов с переданными параметрами для последующей проверки, а может сам выкидывать исключения при некорректно переданных данных. Т.е. именно мок-объект проверяет корректность поведения тестируемого объекта.
— fake object (фальшивый объект), используется в основном чтобы запускать (незапускаемые) тесты (быстрее) и ускорения их работы. Эдакая замена тяжеловесного внешнего зависимого объекта его легковесной реализацией. Основные примеры — эмулятор для конкретного приложения БД в памяти (fake database) или фальшивый вебсервис.
Roy Osherove в книге «The Art of Unit Testing» предлагает упростить данную классификацию и оставляет всего три типа тестовых объектов — Fakes, Stubs и Mocks. Причем Fake может быть как stub-ом, так и mock-ом, а тестовый шпион становится mock-ом. Хотя лично мне не очень нравится перемешивание тестового шпиона и мок-объекта.
Запутанно? Возможно. У данной статьи была задача показать, что написание правильных модульных тестов — достаточно сложная задача, и что не всё то mock, что создаётся в посредством mock-frameworks.
Надеюсь, я сумел подвести читателя к основной мысли — написание качественных модульных тестов дело достаточно непростое. Модульные тесты подчиняются тем же правилам, что и основное приложение, которое они тестируют. При написании модульных тестов следует тестировать модули настолько изолированно друг от друга, насколько это возможно, и различные разновидности применяемых тестовых объектов в этом, безусловно, помогают. Стиль написания модульных тестов должен быть таким же, как если бы вы писали само приложения — без копипастов, с продуманными классами, поведением, логикой.
Юнит-тестирование в PHP
Язык PHP очень легок для изучения. Это, а так же обилие литературы «Освой _что_угодно_ за 24 часа» породило большое количество, мягко говоря, некачественного кода. Как следствие, рано или поздно любой программист, который выходит за рамки создания гостевой книги или сайта-визитки сталкивается с вопросом: «а если я здесь немножко добавлю, все остальное не ляжет?» Дать ответ на этот вопрос и на многие другие может юнит-тестирование.
В самом начале хочется оговориться — здесь речь не будет идти о TDD и методологиях разработки ПО. В данной статье я попробую показать начинающему PHP-разработчику основы использования модульного тестирования на базе фреймворка PHPUnit
Вместо предисловия
Вначале возникает вполне резонный вопрос: А зачем, если все и так работает?
Здесь все просто. После очередного изменения что-то перестанет работать так как надо — это я вам обещаю. И тогда поиск ошибки может отнять очень много времени. Модульное тестирование может свести этот процесс к считанным минутам. Не будем так же исключать переезд на другую платформу и связанные с ним «подводные камни». Чего только стоит разность в точности вычислений на 64- и 32-разрядных системах. А когда-то вы в первый раз столкнетесь с нюансами вроде
Если вопрос необходимости отпал, то можно приступить к выбору инструмента. Здесь ассортимент в общем-то невелик — PHPUnit (http://www.phpunit.de/) и SimpleTest (http://www.simpletest.org/). Поскольку PHPUnit уже стал стандартом де-факто в тестировании PHP приложений, то на нем и остановимся.
Первое знакомство
Вопросы установки рассматривать не будем: все достаточно внятно изложено на сайте. Попробуем лучше понять, как это все работает.
Допустим, есть у нас некий класс «MyClass», одним из методов реализующий возведение числа в степень. (Здесь вынужден извиниться, но все примеры, в общем-то, высосаны из пальца)
Хочется проверить, правильно ли он работает. О всем классе речь пока не идет — только об одном методе. Напишем для проверки такой тест.
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘MyClass.php’ ;
$ phpunit MyClassTest
.
Time: 0 seconds
OK (1 test, 1 assertion)
Результат выполнения теста «ОК». Казалось бы можно остановиться на этом, но иногда было бы неплохо для проверки скормить методу не один набор данных. PHPUnit предоставляет нам такую возможность — это провайдеры данных. Провайдер данных тоже является паблик-методом (название не существенно), который возвращает массив наборов данных для каждой итеррации. Для использования провайдера необходимо указать его в теге @dataProvider к тесту.
Изменим наш тест следующим образом:
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘MyClass.php’ ;
class MyClassTest extends PHPUnit_Framework_TestCase <
После запуска увидим следующую картину:
Опишу подробнее. Точка, которую в первом выводе теста многие могли принять за опечатку на самом деле таковой не является — это успешно пройденный тест. F(ailure) — соответственно тест не пройденный. Значит в данном случае, было проведено 3 теста, один из который завершился неудачно. В расширенном описании нам было сказано, какой именно, с каким набором исходных данных, с каким реальным и каким ожидаемым результатом. Если бы 2 3 действительно равнялось 9-ти, то мы увидели бы таким образом ошибку в нашем сценарии.
Здесь, как мне кажется, есть смысл отвлечься от несколько абстрактной практики и перейти ко вполне конкретной теории. А именно, описать какими же assert-методами мы располагаем для проверки поведения тестируемых сценариев.
Два самых простых — это assertFalse() и assertTrue(). Проверяют, является ли полученное значение false и true соответственно. Далее идут уже упомянутый assertEquals() и обратный ему assertNotEquals(). В их использовании есть нюансы. Так при сравнении чисел с плавающей точкой есть возможность указать точность сравнения. Так же эти методы используются для сравнения экземпляров класса DOMDocument, массивов и любых объектов (в последнем случае равенство будет установлено, если атрибуты объектов содержат одинаковые значения). Так же следует упомянуть assertNull() и assertNotNull() которые проверяют соответствие параметра типу данных NULL (да-да, не забываем, что в PHP это отдельный тип данных). Этим возможные сравнения не ограничиваются. Нет смысла в рамках этой статьи заниматься перепечаткой документации, потому приведу по возможности структурированный список всех возможных методов. Более детально интересующиеся могут прочитать здесь
Базовые методы сравнения
assertTrue() / assertFalse()
assertEquals() / assertNotEquals()
assertGreaterThan()
assertGreaterThanOrEqual()
assertLessThan()
assertLessThanOrEqual()
assertNull() / assertNotNull()
assertType() / assertNotType()
assertSame() / assertNotSame()
assertRegExp() / assertNotRegExp()
Методы сравнения массивов
assertArrayHasKey() / assertArrayNotHasKey()
assertContains() / assertNotContains()
assertContainsOnly() / assertNotContainsOnly()
ООП специфичные методы
assertClassHasAttribute() / assertClassNotHasAttribute()
assertClassHasStaticAttribute() / assertClassNotHasStaticAttribute()
assertAttributeContains() / assertAttributeNotContains()
assertObjectHasAttribute() / assertObjectNotHasAttribute()
assertAttributeGreaterThan()
assertAttributeGreaterThanOrEqual()
assertAttributeLessThan()
assertAttributeLessThanOrEqual()
Методы сравнения файлов
assertFileEquals() / assertFileNotEquals()
assertFileExists() / assertFileNotExists()
assertStringEqualsFile() / assertStringNotEqualsFile()
Методы сравнения XML
assertEqualXMLStructure()
assertXmlFileEqualsXmlFile() / assertXmlFileNotEqualsXmlFile()
assertXmlStringEqualsXmlFile() / assertXmlStringNotEqualsXmlFile()
assertXmlStringEqualsXmlString() / assertXmlStringNotEqualsXmlString()
Разное
assertTag()
assertThat()
Исключения
Если еще не надоело, то вернемся к практике, а именно к обработке исключений. Для начала модифицируем наш тестируемый класс — введем в него метод, который будет это исключение выбрасывать.
class MathException extends Exception < >;
Теперь надо создать тест, который будет завершаться успешно в том случае, если при определенном наборе данных будет вызвано это исключение. Задать требуемое исключение можно как минимум двумя способами — добавив к тесту @expectedException либо вызвав в тесте метод setExpectedException().
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘MyClass.php’ ;
class MyClassTest extends PHPUnit_Framework_TestCase <
Тесты, в общем-то, абсолютно идентичны. Выбор способа остается на ваше усмотрение. Помимо механизмов предоставляемых непосредственно PHPUnit, для тестирования исключений можно воспользоваться стандартным try <…>catch (), к примеру, так:
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘MyClass.php’ ;
class MyClassTest extends PHPUnit_Framework_TestCase <
В этом примере мы так же видим не рассмотренный ранее способ завершения теста с помощью вызова метода fail(). Вывод теста будет следующим:
F
Time: 0 seconds
There was 1 failure:
1) testDivision3(MyClassTest)
Not raise an exception
/home/user/unit/MyClassTest.php:50
Принадлежности
Базовые методы тестирования мы освоили. Можно ли улучшить наш тест? Да. Написанный c начала этой статьи класс проводит несколько тестов, в каждом из которых создается экземпляр тестируемого класса, что абсолютно излишне, потому как PHPUnit предоставляет в наше пользование механизм принадлежностей теста (fixtures). Установить их можно защищенным методом setUp(), который вызывается один раз перед началом каждого теста. После окончания теста вызывается метод tearDown(), в котором мы можем провести «сборку мусора». Таким образом, исправленный тест может выглядеть так:
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘MyClass.php’ ;
class MyClassTest extends PHPUnit_Framework_TestCase <
Наборы тестов
После того, как код нескольких классов будет покрыт тестами, становится довольно таки неудобно запускать каждый тест по отдельности. Здесь нам на помощь могут прийти наборы тестов — несколько связанных единой задачей тестов можно объединить в набор и запускать соответственно его. Наборы реализованы классом PHPUnit_Framework_TestSuite. Необходимо создать экземпляр этого класса и добавить в него необходимые тесты с помощью метода addTestSuite(). Так же с помощью метода addTest() возможно добавление другого набора.
require_once ‘PHPUnit/Framework.php’ ;
// подключаем файлы с тестами
require_once ‘MyClassTest.php’ ;
require_once ‘PHPUnit/Framework.php’ ;
// подключаем файл с набором тестов
require_once ‘SpecificTests.php’ ;
А теперь представим себе набор тестов для сценария, работающего с БД. Неужели нам в каждом тесте придется подключаться к базе? Нет — не придется. Для этого можно создать свой класс унаследованный от PHPUnit_Framework_TestSuite, определить его методы setUp() и tearDown() для инициализации интерфейса БД и просто передать его в тест атрибутом sharedFixture. Базы данных мы оставим на потом, а пока попробуем создать собственный набор тестов для уже имеющегося класса.
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘MyClass.php’ ;
class MyClassTest extends PHPUnit_Framework_TestCase <
class MySuite extends PHPUnit_Framework_TestSuite <
Здесь мы в sharedFixture положили экземпляр тестируемого класса, а в тесте просто его использовали — решение не слишком красивое (я бы даже сказал, вообще не красивое), но общее представление о наборах тестов и передаче принадлежностей между тестами оно дает. Если наглядно изобразить очередность вызова методов, то получится нечто вроде такого:
MySuite::setUp()
MyClassTest::setUp()
MyClassTest::testPower()
MyClassTest::tearDown()
MyClassTest::setUp()
MyClassTest::testDivision()
MyClassTest::tearDown()
.
MySuite::tearDown()
Дополнительные возможности
Помимо всего вышеизложенного может возникнуть необходимость проверить не только расчеты и поведение сценария, но так же вывод и скорость отработки. Для этого в наше распоряжение предоставлены расширения PHPUnit_Extensions_OutputTestCase и PHPUnit_Extensions_PerformanceTestCase соответственно. Добавим в наш тестируемый класс еще один метод, и проверим правильно ли он работает.
require_once ‘PHPUnit/Framework.php’ ;
require_once ‘PHPUnit/Extensions/OutputTestCase.php’ ;
require_once ‘PHPUnit/Extensions/PerformanceTestCase.php’ ;
require_once ‘MyClass.php’ ;
class MyClassOutputTest extends PHPUnit_Extensions_OutputTestCase <
class MyClassPerformanceTest extends PHPUnit_Extensions_PerformanceTestCase <
class MyClassTest extends PHPUnit_Framework_TestCase <
Задать ожидаемый вывод сценария можно с помощью методов expectOutputString() или expectOutputRegex(). А для метода setMaxRunningTime() планируемое время отработки указывается в секундах. Для того, что бы эти тесты запускались вместе с уже написанными их всего лишь надо добавить к нашему набору:
class MySuite extends PHPUnit_Framework_TestSuite <
Пропускаем тесты
И напоследок рассмотрим ситуацию, в которой некоторые тесты необходимо пропускать по каким либо причинам. К примеру в том случае, когда на тестируемой машине отсутствует какое-либо расширение PHP, можно убедившись в его отсутствии пометить тест, как пропущенный добавив к его коду следующее:
Либо в том случае, когда тест написан для кода, которого еще нет в сценарии (не редкая для TDD ситуация) его можно пометить как не реализованный с помощью метода markTestIncomplete()