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




TestSuite

def run(self):

result = TestResult()

for test in tests:

test.run(result)

return result


Здесь оператор цикла «for test in tests» выполняет итерации по всем элементам последовательности tests, присваивает их по одному переменной цикла test и запускает соответствующий тест. Однако шаблон «Компоновщик» (Composite) подразумевает, что набор объектов должен обладать точно таким же интерфейсом, каким обладает отдельный объект. Если мы передаем параметр методу TestCase.run(), значит, мы должны передавать точно такой же параметр методу TestSuite.run(). Можно использовать одну из трех альтернатив.

• Воспользоваться встроенным в язык Python механизмом параметров со значениями по умолчанию. К сожалению, значение параметра по умолчанию вычисляется во время компиляции, но не во время выполнения, а мы не хотим повторно использовать один и тот же объект TestResult.

• Разделить метод на две части – одна создает объект TestResult, а вторая выполняет тест, используя переданный ей объект TestResult. Я не могу придумать хороших имен для двух частей метода, а это означает, что данная стратегия не является самой лучшей.

• Создавать объекты TestResult в вызывающем коде.


Мы будем создавать объекты TestResult в вызывающем коде. Этот шаблон называется «Накапливающий параметр» (Collecting Parameter).


TestCaseTest

def testSuite(self):

suite = TestSuite()

suite.add(WasRun("testMethod"))

suite.add(WasRun("testBrokenMethod"))

result = TestResult()

suite.run(result)

assert("2 run, 1 failed" == result.summary())


При использовании данного подхода метод run() не возвращает никакого явного значения:


TestSuite

def run(self, result):

for test in tests:

test.run(result)


TestCase

def run(self, result):

result.testStarted()

self.setUp()

try:

method = getattr(self, self.name)

method()

except:

result.testFailed()

self.tearDown()


Теперь мы можем облагородить обращение к тестовым методам в конце файла:


suite = TestSuite()

suite.add(TestCaseTest("testTemplateMethod"))

suite.add(TestCaseTest("testResult"))

suite.add(TestCaseTest("testFailedResultFormatting"))

suite.add(TestCaseTest("testFailedResult"))

suite.add(TestCaseTest("testSuite"))

result = TestResult()

suite.run(result)

print(result.summary())

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

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

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

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

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

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

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