Читаем Экстремальное программирование: Разработка через тестирование полностью

Мы также можем упростить сами тесты. В обоих случаях мы создаем экземпляр класса WasRun, а ведь задача создания тестовых объектов возлагается на подготовительный этап – именно об этом мы с вами говорили. Стало быть, мы можем создать объект WasRun в методе setUp(), а затем использовать его в тестовых методах. Каждый тестовый метод выполняется в отдельном экземпляре класса TestCaseTest, поэтому два разных теста не могут быть взаимозависимы. (Мы исходим из того, что объект не будет взаимодействовать с внешним миром некоторым непредусмотренным уродливым способом, например путем изменения значений глобальных переменных.)

TestCaseTest

def setUp(self):

self.test = WasRun("testMethod")

def testRunning(self):

self.test.run()

assert(self.test.wasRun)

def testSetUp(self):

self.test.run()

assert(self.test.wasSetUp)

Вызов тестового метода

Вызов метода setUp перед обращением к методу

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

Метод tearDown должен вызываться даже в случае неудачи теста

Выполнение нескольких тестов

Отчет о результатах

Теперь сделаем так, чтобы после выполнения тестового метода обязательно выполнялся метод tearDown().

В данной главе мы

• решили, что на текущий момент тестов важнее простота, чем их производительность;

• написали тест для метода setUp() и реализовали этот метод;

• использовали метод setUp(), чтобы упростить тестируемый объект-контейнер теста;

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

<p>20. Убираем со стола (метод tearDown)</p>

Вызов тестового метода

Вызов метода setUp перед обращением к методу

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

Метод tearDown должен вызываться даже в случае неудачи теста

Выполнение нескольких тестов

Отчет о результатах

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

Как можно протестировать выполнение метода tearDown()? Проще всего – использовать еще один флаг. Однако все эти флаги начинают сбивать меня с толку. Если мы будем использовать флаги, мы упустим один очень важный аспект: метод setUp() должен быть выполнен непосредственно перед обращением к тестовому методу, а метод tearDown() – непосредственно после обращения к тестовому методу. Чтобы убедиться в этом, я намерен изменить стратегию тестирования. Предлагаю создать миниатюрный журнал, в котором будет отмечаться последовательность выполнения методов. Каждый метод будет добавлять в конец журнала соответствующую запись. Таким образом, просмотрев журнал, мы сможем установить порядок выполнения методов.

Вызов тестового метода

Вызов метода setUp перед обращением к методу

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

Метод tearDown должен вызываться даже в случае неудачи теста

Выполнение нескольких тестов

Отчет о результатах

Строка журнала в классе WasRun

WasRun

def setUp(self):

self.wasRun = None

self.wasSetUp = 1

self.log = "setUp "

Теперь можно изменить метод testSetUp(), чтобы вместо флага он проверял содержимое журнала:

TestCaseTest

def testSetUp(self):

self.test.run()

assert("setUp " == self.test.log)

После этого мы можем удалить флаг wasSetUp. Мы также можем добавить в журнал запись о выполнении метода:

WasRun

def testMethod(self):

self.wasRun = 1

self.log = self.log + "testMethod "

В результате нарушается работа теста testSetUp(), так как в момент выполнения этого метода журнал содержит строку «setUp testMethod». Изменяем ожидаемое значение:

TestCaseTest

def testSetUp(self):

self.test.run()

assert("setUp testMethod " == self.test.log)

Теперь этот тест выполняет работу обоих тестов, поэтому можно удалить testRunning и переименовать testSetUp:

TestCaseTest

def setUp(self):

self.test = WasRun("testMethod")

def testTemplateMethod(self):

self.test.run()

assert("setUp testMethod " == self.test.log)

Мы используем экземпляр класса WasRun всего в одном месте, поэтому необходимо отменить добавленный ранее хитрый трюк, связанный с setUp():

TestCaseTest

def testTemplateMethod(self):

test = WasRun("testMethod")

test.run()

assert("setUp testMethod " == test.log)

Перейти на страницу:

Все книги серии Библиотека программиста

Программист-фанатик
Программист-фанатик

В этой книге вы не найдете описания конкретных технологий, алгоритмов и языков программирования — ценность ее не в этом. Она представляет собой сборник практических советов и рекомендаций, касающихся ситуаций, с которыми порой сталкивается любой разработчик: отсутствие мотивации, выбор приоритетов, психология программирования, отношения с руководством и коллегами и многие другие. Подобные знания обычно приходят лишь в результате многолетнего опыта реальной работы. По большому счету перед вами — ярко и увлекательно написанное руководство, которое поможет быстро сделать карьеру в индустрии разработки ПО любому, кто поставил себе такую цель. Конечно, опытные программисты могут найти некоторые идеи автора достаточно очевидными, но и для таких найдутся темы, которые позволят пересмотреть устоявшиеся взгляды и выйти на новый уровень мастерства. Для тех же, кто только в самом начале своего пути как разработчика, чтение данной книги, несомненно, откроет широчайшие перспективы. Издательство выражает благодарность Шувалову А. В. и Курышеву А. И. за помощь в работе над книгой.

Чед Фаулер

Программирование, программы, базы данных / Программирование / Книги по IT

Похожие книги