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

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

ResultListenerTest

def testNotification(self):

result = TestResult()

listener = ResultListener()

result.addListener(listener)

WasRun("testMethod"). run(result)

assert 1 == listener.count

Тест нуждается в объекте, который подсчитывал бы количество оповещений:

ResultListener

class ResultListener:

def __init__(self):

self.count = 0

def startTest(self):

self.count = self.count + 1

Подождите-ка! Зачем нам нужен отдельный объект Listener? Все необходимые функции мы можем возложить на объект TestCase. В этом случае объект TestCase становится подобием поддельного объекта.

ResultListenerTest

def testNotification(self):

self.count = 0

result = TestResult()

result.addListener(self)

WasRun("testMethod"). run(result)

assert 1 == self.count

def startTest(self):

self.count = self.count + 1

Тесты, написанные с использованием шаблона «Самошунтирование» (Self Shunt), как правило, читаются лучше, чем тесты, написанные без него. Предыдущий тест является неплохим примером. Счетчик был равен 0, а затем стал равен 1. Вы можете проследить за последовательностью действий прямо в коде теста. Почему счетчик стал равен 1? Очевидно, кто-то обратился к методу startTest(). Где произошло обращение к методу startTest()? Это произошло в начале выполнения теста. Вторая версия теста использует два разных значения переменной count в одном месте, в то время как первая версия присваивает переменной count значение 0 в одном классе и проверяет эту переменную на равенство значению 1 в другом.

Возможно, при использовании шаблона «Самошунтирование» (Self Shunt) вам потребуется применить шаблон рефакторинга «Выделение интерфейса» (Extract Interface), чтобы получить интерфейс, который должен быть реализован вашим тестом. Вы должны сами определить, что проще: выделение интерфейса или тестирование существующего объекта в рамках концепции «черный ящик». Однако я часто замечал, что интерфейсы, выделенные при выполнении самошунтирования, в дальнейшем, как правило, оказываются полезными для решения других задач.

В результате использования шаблона «Самошунтирование» (Self Shunt) вы можете наблюдать, как тесты в языке Java обрастают разнообразными причудливыми интерфейсами. В языках с оптимистической типизацией класс теста обязан реализовать только те операции интерфейса, которые действительно используются в процессе выполнения теста. Однако в Java вы обязаны реализовать абсолютно все операции интерфейса несмотря на то, что некоторые из них будут пустыми. По этой причине интерфейсы следует делать как можно менее емкими. Реализация каждой операции должна либо возвращать значение, либо генерировать исключение – это зависит от того, каким образом вы хотите быть оповещены о том, что произошло нечто неожиданное.

Строка-журнал (Log String)

Как можно убедиться в том, что обращение к методам осуществляется в правильном порядке? Создайте строку, используйте ее в качестве журнала. При каждом обращении к методу добавляйте в строку-журнал некоторое символьное сообщение.

Данный прием продемонстрирован ранее, в главе 20, где мы тестировали порядок обращения к методам класса TestCase. В нашем распоряжении имеется шаблонный метод, который, как мы предполагаем, обращается к методу setUp(), затем к тестовому методу, а затем к методу tearDown(). Нам хотелось бы убедиться в том, что обращение к методам осуществляется в указанном порядке. Реализуем методы так, чтобы каждый из них добавлял свое имя в строку-журнал. Исходя из этого можно написать следующий тест:

def testTemplateMethod(self):

test = WasRun("testMethod")

result = TestResult()

test.run(result)

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

Реализация тоже очень проста:

WasRun

def setUp(self):

self.log = "setUp "

def testMethod(self):

self.log = self.log + "testMethod "

def tearDown(self):

self.log = self.log + "tearDown "

Шаблон «Строка-журнал» (Log String) особенно полезен в случае, когда вы реализуете шаблон «Наблюдатель» (Observer) и желаете протестировать порядок поступления оповещений. Если вас прежде всего интересует, какие именно оповещения генерируются, однако порядок их поступления для вас не важен, вы можете создать множество строк, добавлять строки в множество при обращении к методам и в выражении assert использовать операцию сравнения множеств.

Шаблон «Строка-журнал» (Log String) хорошо сочетается с шаблоном «Самошунтирование» (Self Shunt). Объект-тест реализует методы шунтируемого интерфейса так, что каждый из них добавляет запись в строку-журнал, затем проверяется корректность этих записей.

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

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

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

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

Чед Фаулер

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

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