Чтобы реализовать функциональность методов testStarted() и testFailed(), воспользуемся двумя счетчиками: счетчиком запущенных тестов и счетчиком неудачных тестов:
TestResult
def __init__(self):
self.runCount = 0
self.errorCount = 0
def testFailed(self):
self.errorCount = self.errorCount + 1
Если счетчик будет работать корректно (мы должны были бы это протестировать, однако кофе, похоже, ударил мне в голову), отчет будет напечатан корректно:
TestResult
def summary(self):
return "%d run, %d failed" % (self.runCount, self.failureCount)
Теперь можно предположить, что, если обращение к методу testFailed() будет выполнено корректно, мы получим на экране желаемый результат. Но где следует вызвать этот метод? В обработчике исключения, перехваченного в процессе выполнения тестового метода:
TestCase
def run(self):
result = TestResult()
result.testStarted()
self.setUp()
try:
method = getattr(self, self.name)
method()
except:
result.testFailed()
self.tearDown()
return result
В этом коде присутствует одно тонкое место: если исключение возникает во время выполнения метода setUp(), оно не будет перехвачено. Это означает, что в определенной степени тесты зависят друг от друга. Однако прежде, чем менять код, мы должны написать еще один тест. (Я научил мою старшую дочку Бетани программировать в стиле TDD, когда ей было 12 лет. Это самый первый стиль программирования, с которым она познакомилась. Она не умеет программировать иначе и абсолютно уверена, что добавлять в программу новый функциональный код можно только в случае, если существует тест, который терпит неудачу. Однако более опытные программисты, как правило, вынуждены напоминать себе о том, что сначала необходимо писать тесты, а потом – код, заставляющий их выполняться.) Я оставляю этот следующий тест и его реализацию вам в качестве самостоятельного упражнения (мои пальцы опять устали):
Метод tearDown должен вызываться даже в случае неудачи теста
Выполнение нескольких тестов
Перехват и отчет об ошибках setUp
Далее мы сделаем так, чтобы наша инфраструктура смогла запустить несколько тестов подряд.
В данной главе мы
• обеспечили успешное выполнение нашего теста меньшего масштаба;
• заново приступили к реализации более крупного теста;
• обеспечили успешное выполнение крупного теста, воспользовавшись механизмом, реализованным для маленького теста;
• обратили внимание на потенциальную проблему, но вместо того, чтобы немедленно браться за ее решение, добавили соответствующую пометку в список задач.
23. Оформляем тесты в набор
Метод tearDown должен вызываться даже в случае неудачи теста
Выполнение нескольких тестов
Перехват и отчет об ошибках setUp
Мы не можем оставить работу над xUnit, не реализовав класс TestSuite, представляющий собой набор тестов. Конец нашего файла, где мы запускаем все наши тесты, выглядит весьма неопрятно:
print(TestCaseTest(«testTemplateMethod»). run(). summary())
print(TestCaseTest("testResult"). run(). summary())
print(TestCaseTest("testFailedResultFormatting"). run(). summary())
print(TestCaseTest("testFailedResult"). run(). summary())
Дублирование – это всегда плохо, за исключением случаев, когда вы используете его в качестве мотивации для поиска недостающего элемента дизайна. В данном случае нам хотелось бы сгруппировать тесты и запустить их при помощи одной команды. (Мы приложили массу усилий для изоляции тестов, однако все эти усилия не окупят себя, если мы будем запускать тесты по одному.) Еще одна хорошая причина, по которой было бы неплохо реализовать TestSuite, заключается в том, что этот класс хорошо демонстрирует использование шаблона «Компоновщик» (Composite), – мы хотим, чтобы набор тестов вел себя в точности так же, как единичный тест.
Мы хотим обладать возможностью создать набор тестов (объект TestSuite), добавить в него несколько тестов и получить общий результат выполнения всех этих тестов:
TestCaseTest
def testSuite(self):
suite = TestSuite()
suite.add(WasRun("testMethod"))
suite.add(WasRun("testBrokenMethod"))
result = suite.run()
assert("2 run, 1 failed" == result.summary())
Для успешного выполнения теста создадим в объекте TestSuite список тестов и реализуем метод add(), который просто добавляет тест, переданный в качестве аргумента, в список:
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии