Тестирование в Python [unittest]. Часть 3. TestSuite. Загрузка и запуск тестов
Третья часть из цикла статей про unittest в Python посвящена TestSuite – второй важной составляющей framework’а для тестирования, а также загрузке и запуску тестов (классы TestLoader, TestResult, TextTestRunner).
Для более полного изучения возможностей рассматриваемых классов рекомендуем обратиться к официальной документации.
Класс TestSuite
Класс TestSuite используется для объединения тестов в группы, которые могут включать в себя как отдельные тесты так и заранее созданные группы. Помимо этого, TestSuite предоставляет интерфейс, позволяющий TestRunner’у, запускать тесты. Разберем более подробно методы класса TestSuite.
addTest(test)
Добавляет TestCase или TestSuite в группу.
addTests(tests)
Добавляет все TestCase и TestSuite объекты в группу, итеративно проходя по элементам переменной tests.
Запускает тесты из данной группы.
countTestCases()
Возвращает количество тестов в данной группе (включает в себя как отдельные тесты, так и подгруппы).
Рассмотрим пример использования TestSuite.
В качестве кода, который нужно протестировать, возьмем уже знакомый нам модуль calc.py.
def add(a, b): return a + b def sub(a, b): return a-b def mul(a, b): return a * b def div(a, b): return a / b
За основу модуля с тестами примем тот, что приведен в конце первой статьи. Назовем его calc_tests.py.
import unittest import calc class CalcTest(unittest.TestCase): def test_add(self): self.assertEqual(calc.add(1, 2), 3) def test_sub(self): self.assertEqual(calc.sub(4, 2), 2) def test_mul(self): self.assertEqual(calc.mul(2, 5), 10) def test_div(self): self.assertEqual(calc.div(8, 4), 2)
Для запуска тестов дополнительно создадим модуль test_runner.py и добавим в него следующий код.
import unittest import calc_tests calcTestSuite = unittest.TestSuite() calcTestSuite.addTest(unittest.makeSuite(calc_tests.CalcTest)) runner = unittest.TextTestRunner(verbosity=2) runner.run(calcTestSuite)
Все модули должны находиться в одном каталоге. Для запуска тестов используйте команду:
В примере мы использовали класс TextTestRunner, о нем будет рассказано чуть позже.
Расширим функционал модуля calc, для этого добавим в него пару методов: первый будет вычислять квадратный корень, второй – возводить число в определенную степень.
def add(a, b): return a + b def sub(a, b): return a-b def mul(a, b): return a * b def div(a, b): return a / b def sqrt(a): return a**0.5 def pow(a, b): return a**b
Добавим тесты для новых функций, создав новый класс с именем CalcExTests (расширенные функции калькулятора) с тестами для sqrt() и pow(), а класс CalcTest переименуем в CalcBasicTests (базовые функции калькулятора).
import unittest import calc class CalcBasicTests(unittest.TestCase): def test_add(self): self.assertEqual(calc.add(1, 2), 3) def test_sub(self): self.assertEqual(calc.sub(4, 2), 2) def test_mul(self): self.assertEqual(calc.mul(2, 5), 10) def test_div(self): self.assertEqual(calc.div(8, 4), 2) class CalcExTests(unittest.TestCase): def test_sqrt(self): self.assertEqual(calc.sqrt(4), 2) def test_pow(self): self.assertEqual(calc.pow(3, 3), 27)
import unittest import calc_tests calcTestSuite = unittest.TestSuite() calcTestSuite.addTest(unittest.makeSuite(calc_tests.CalcBasicTests)) calcTestSuite.addTest(unittest.makeSuite(calc_tests.CalcExTests)) print("count of tests: " + str(calcTestSuite.countTestCases()) + "\n") runner = unittest.TextTestRunner(verbosity=2) runner.run(calcTestSuite)
Запустив test_runner.py получим следующий результат.
count of tests: 6 test_add (calc_tests.CalcBasicTests) . ok test_div (calc_tests.CalcBasicTests) . ok test_mul (calc_tests.CalcBasicTests) . ok test_sub (calc_tests.CalcBasicTests) . ok test_pow (calc_tests.CalcExTests) . ok test_sqrt (calc_tests.CalcExTests) . ok ---------------------------------------------------------------------- Ran 6 tests in 0.000s OK
Как видно из примера: было запущено шесть тестов, четыре из класса CalcBasicTests и два из CalcExTests, все тесты завершились удачно. Количество тестов в группе указано в самой первой строке вывода: count of tests: 6.
Загрузка и запуск тестов
Рассмотрим более подробно вопросы загрузки и запуска тестов.
Класс TestLoader
Начнем с класса TestLoader. Этот класс используется для создания групп из классов и модулей. Среди методов TestLoader можно выделить: loadTestsFromTestCase(testCaseClass) , возвращающий группу со всеми тестами из класса testCaseClass. Напоминаем, что под тестом понимается модуль, начинающийся со слова “test”. Используя этот метод, можно создать список групп тестов, где каждая группа создается на базе классов-наследников от TestCase, объединенных предварительно в список. Для демонстрации данного подхода модифицируем test_runner .py (написано по материалам dr.dobb’s).
import unittest import calc_tests testCases = [] testCases.append(calc_tests.CalcBasicTests) testCases.append(calc_tests.CalcExTests) testLoad = unittest.TestLoader() suites = [] for tc in testCases: suites.append(testLoad.loadTestsFromTestCase(tc)) res_suite = unittest.TestSuite(suites ) runner = unittest.TextTestRunner(verbosity=2) runner.run(res_suite)
Рассмотрим ещё несколько методов из TestLoader.
loadTestsFromModule(module, pattern=None)
Загружает все тесты из модуля module. Если модуль поддерживает load_tests протокол, то будет вызвана соответствующая функция модуля и ей будет передан в качестве аргумента (третьим по счету) параметр pattern.
loadTestsFromName(name, module=None)
Загружает тесты в соответствии с параметром name. Параметр name – это имя, разделенное точками. С помощью этого имени указывается уровень, начиная с которого будут добавляться тесты.
getTestCaseNames(testCaseClass)
Возвращает список имен методов-тестов из класса testCaseClass.
Приведем примеры того, как можно использовать данные методы. Для демонстрации loadTestsFromModule изменим модуль test_runner.py.
import unittest import calc_tests testLoad = unittest.TestLoader() suites = testLoad.loadTestsFromModule(calc_tests) runner = unittest.TextTestRunner(verbosity=2) runner.run(suites)
Запустим модуль test_runner.py.
Результатом выполнения будет подробный отчет о прохождении шести тестов:
test_add (calc_tests.CalcBasicTests) . ok test_div (calc_tests.CalcBasicTests) . ok test_mul (calc_tests.CalcBasicTests) . ok test_sub (calc_tests.CalcBasicTests) . ok test_pow (calc_tests.CalcExTests) . ok test_sqrt (calc_tests.CalcExTests) . ok ---------------------------------------------------------------------- Ran 6 tests in 0.016s OK
Если в модуле test_runner.py заменить строку
то будут выполнены только тесты из класса CalcBasicTests.
test_add (calc_tests.CalcBasicTests) . ok test_div (calc_tests.CalcBasicTests) . ok test_mul (calc_tests.CalcBasicTests) . ok test_sub (calc_tests.CalcBasicTests) . ok ---------------------------------------------------------------------- Ran 4 tests in 0.002s OK
Класс TestResult
Класс TestResult используется для сбора информации о результатах прохождения тестов. Подробную информацию по атрибутам и классам этого метода можно найти в официальной документации.
Для демонстрации возможностей класса TestResult модифицируем модуль test_runner.py:
import unittest import calc_tests testLoad = unittest.TestLoader() suites = testLoad.loadTestsFromModule(calc_tests) testResult = unittest.TestResult() runner = unittest.TextTestRunner(verbosity=1) testResult = runner.run(suites) print("errors") print(len(testResult.errors)) print("failures") print(len(testResult.failures)) print("skipped") print(len(testResult.skipped)) print("testsRun") print(testResult.testsRun)
Запустив его, получим следующий результат:
. ---------------------------------------------------------------------- Ran 6 tests in 0.001s OK errors 0 failures 0 skipped 0 testsRun 6
Класс TextTestRunner
Объекты класса TextTestRunner используются для запуска тестов. Среди параметров, которые передаются конструктору класса, можно выделить verbosity, по умолчанию он равен 1, если создать объект с verbosity=2, то будем получать расширенную информацию о результатах прохождения тестов. Для запуска тестов используется метод run(), которому в качестве аргумента передается класс-наследник от TestCase или группа (TestSuite).
В наших примерах TextTestRunner используется в модуле test_runner.py в строчках:
В первой строке создается объект класса TextTestRunner с verbosity=2, а во второй строке запускаются тесты из группы suites, результат тестирования попадает в объект testResult, атрибуты которого можно анализировать в дальнейшем.