Контекстный менеджер 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 идентифицирует закрытый блок подтеста, возвращенный менеджером контекста.

Если произойдет сбой, тестовый пример будет помечен как неудавшийся. Однако он возобновляет выполнение в конце вложенного блока, позволяя выполнить дальнейший тестовый код.

Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *