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

Самошунтирование (Self Shunt)

Самошунтирование (Self Shunt)

Как можно убедиться в том, что один объект корректно взаимодействует с другим? Заставьте тестируемый объект взаимодействовать не с целевым объектом, а с вашим тестом.

Предположим, что вы хотите динамически обновлять зеленую полосу, отображаемую в рамках тестируемого пользовательского интерфейса. Если мы сможем подключить наш объект к объекту 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 вы обязаны реализовать абсолютно все операции интерфейса несмотря на то, что некоторые из них будут пустыми. По этой причине интерфейсы следует делать как можно менее емкими. Реализация каждой операции должна либо возвращать значение, либо генерировать исключение – это зависит от того, каким образом вы хотите быть оповещены о том, что произошло нечто неожиданное.

Оглавление книги


Генерация: 0.298. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз