Тестирование в Python [unittest]. Часть 3. TestSuite. Загрузка и запуск тестов

Тестирование в Python [unittest]. Часть 3. TestSuite. Загрузка и запуск тестов

Nuances of programming

Предыдушие части: Часть 1, Часть 2

Класс TestSuite

Класс TestSuite используется для объединения тестов в группы, которые могут включать в себя как отдельные тесты так и заранее созданные группы. Помимо этого, TestSuite предоставляет интерфейс, позволяющий TestRunner’у, запускать тесты. Разберем более подробно методы класса TestSuite.

addTest(test)

Добавляет TestCase или TestSuite в группу.

addTests(tests)

Добавляет все TestCase и TestSuite объекты в группу, итеративно проходя по элементам переменной tests.

run(result)

Запускает тесты из данной группы.

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)


Все модули должны находиться в одном каталоге. Для запуска тестов используйте команду:

>python test_runner.py


В примере мы использовали класс TextTestRunner, о нем будет рассказано чуть позже.

Расширим функционал модуля calc, для этого добавим в него пару методов: первый будет вычислять квадратный корень, второй – возводить число в определенную степень.

Модуль 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

def sqrt(a):
    return a**0.5

def pow(a, b):
    return a**b


Добавим тесты для новых функций, создав новый класс с именем CalcExTests (расширенные функции калькулятора) с тестами для sqrt() и pow(), а класс CalcTest переименуем в CalcBasicTests (базовые функции калькулятора).

Модуль calc_tests.py

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)


Модуль test_runner.py

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).

Модуль test_runner.py

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.

Модуль 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.

>python 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 заменить строку

suites = testLoad.loadTestsFromModule(calc_tests)

на

suites = testLoad.loadTestsFromName(“calc_tests.CalcBasicTests”)

то будут выполнены только тесты из класса 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 в строчках:

runner = unittest.TextTestRunner(verbosity=2)

testResult = runner.run(suites)

В первой строке создается объект класса TextTestRunner с verbosity=2, а во второй строке запускаются тесты из группы suites, результат тестирования попадает в объект testResult, атрибуты которого можно анализировать в дальнейшем.



Источник

Report Page