Контекстный менеджер subTest() Unittest в Python
Рассмотрим, как определять параметризованные тесты с помощью контекстного менеджера subTest() Unittest в Python.
Знакомство с контекстным менеджером subTest
- Сначала создайте новый модуль с именем «pricing.py» и определите функцию Calculation() следующим образом:
def calculate(price, tax=0, discount=0): return round((price - discount) *(1+tax), 2)
Функция Calculation() вычисляет чистую цену на основе цены, налога и скидки.
- Во-вторых, создайте тестовый модуль test_pricing.py для проверки функции Calculation():
import unittest from pricing import calculate class TestPricing(unittest.TestCase): def test_calculate(self): pass
Чтобы протестировать функцию Calculation(), вам нужно придумать несколько тестовых примеров, например:
- Имеет цену без налога и скидки.
- Цена указана с налогом, но без скидки.
- Имеется цена без налога, но со скидкой.
- Цена с налогом и скидкой.
Чтобы охватить эти случаи, вам необходимо иметь различные методы тестирования. Или вы можете определить один метод тестирования и предоставить данные тестирования из списка случаев. Например:
import unittest from pricing import calculate class TestPricing(unittest.TestCase): def test_calculate(self): items =( {'case': 'No tax, no discount', 'price': 10, 'tax': 0, 'discount': 0, 'net_price': 10}, {'case': 'Has tax, no discount', 'price': 10, 'tax': 0.1, 'discount': 0, 'net_price': 10}, {'case': 'No tax, has discount', 'price': 10, 'tax': 0, 'discount': 1, 'net_price': 10}, {'case': 'Has tax, has discount', 'price': 10, 'tax': 0.1, 'discount': 1, 'net_price': 9.9}, ) for item in items: with self.subTest(item['case']): net_price = calculate( item['price'], item['tax'], item['discount'] ) self.assertEqual( net_price, item['net_price'] )
Запустите тест:
python -m unittest test_pricing -v
Выход:
test_calculate(test_pricing.TestPricing) ... FAIL ====================================================================== FAIL: test_calculate(test_pricing.TestPricing) ---------------------------------------------------------------------- Traceback(most recent call last): File "D:\python-unit-testing\test_pricing.py", line 26, in test_calculate self.assertEqual( AssertionError: 11.0 != 10 ---------------------------------------------------------------------- Ran 1 test in 0.002s FAILED(failures=1)
Проблема этого подхода в том, что тест останавливается после первой неудачи. Чтобы решить эту проблему, unittest предоставляет вам контекстный менеджер subTest(). Например:
import unittest from pricing import calculate class TestPricing(unittest.TestCase): def test_calculate(self): items =( {'case': 'No tax, no discount', 'price': 10, 'tax': 0, 'discount': 0, 'net_price': 10}, {'case': 'Has tax, no discount', 'price': 10, 'tax': 0.1, 'discount': 0, 'net_price': 10}, {'case': 'No tax, has discount', 'price': 10, 'tax': 0, 'discount': 1, 'net_price': 10}, {'case': 'Has tax, has discount', 'price': 10, 'tax': 0.1, 'discount': 1, 'net_price': 9.9}, ) for item in items: with self.subTest(item['case']): net_price = calculate( item['price'], item['tax'], item['discount'] ) self.assertEqual( net_price, item['net_price'] )
Запустите тест:
python -m unittest test_pricing -v
Выход:
test_calculate(test_pricing.TestPricing) ... ====================================================================== FAIL: test_calculate(test_pricing.TestPricing) [Has tax, no discount] ---------------------------------------------------------------------- Traceback(most recent call last): File "D:\python-unit-testing\test_pricing.py", line 26, in test_calculate self.assertEqual( AssertionError: 11.0 != 10 ====================================================================== FAIL: test_calculate(test_pricing.TestPricing) [No tax, has discount] ---------------------------------------------------------------------- Traceback(most recent call last): File "D:\python-unit-testing\test_pricing.py", line 26, in test_calculate self.assertEqual( AssertionError: 9 != 10 ---------------------------------------------------------------------- Ran 1 test in 0.001s FAILED(failures=2)
Благодаря использованию контекстного менеджера subTest() тест не остановился после первого сбоя. Кроме того, после каждого сбоя отображается очень подробное сообщение, чтобы вы могли изучить ситуацию.
Синтаксис контекстного менеджера subTest()
Ниже показан синтаксис контекстного менеджера subTest():
def subTest(self, msg=_subtest_msg_sentinel, **params):
SubTest() возвращает менеджер контекста. Необязательный параметр msg идентифицирует закрытый блок подтеста, возвращенный менеджером контекста.
Если произойдет сбой, тестовый пример будет помечен как неудавшийся. Однако он возобновляет выполнение в конце вложенного блока, позволяя выполнить дальнейший тестовый код.