Фикстуры в Python: использование в тестировании

Содержание

Знакомство с инструментами тестирования в Python

По определению, тестовое приспособление (фикстура) — это функция или метод, который запускается в Python до и после выполнения блока тестового кода. Другими словами, фикстуры используются в тестировании как этап, выполняемый до или после теста.

Module-level фикстуры

Предположим, у вас есть тестовый модуль под названием test_my_module.py. В test_my_module.py функции setUpModule() и TearDownModule() являются class-level фикстурами.

  • Функция setUpModule() выполняется перед всеми методами тестирования в тестовом модуле.
  • Функция TearDownModule() запускается после всех методов тестового модуля.

См. следующий пример:

import unittest


def setUpModule():
    print('Running setUpModule')


def tearDownModule():
    print('Running tearDownModule')


class TestMyModule(unittest.TestCase):
    def test_case_1(self):
        self.assertEqual(5+5, 10)

    def test_case_2(self):
        self.assertEqual(1+1, 2)

Если вы запустите тест:

python -m unittest -v

Выход:

Running setUpModule
test_case_1(test_my_module.TestMyModule) ... ok
test_case_2(test_my_module.TestMyModule) ... ok
Running tearDownModule

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

В этом примере функция setUpModule() запускается перед всеми методами тестирования, а функция TearDownModule() запускается после всех методов тестирования.

Class-level фикстуры

setUpClass() и TearDownClass() являются class-level фикстурами:

  • SetUpClass() запускается перед всеми тестовыми методами класса.
  • TearDownClass() запускается после всех тестовых методов класса.

Например:

import unittest


def setUpModule():
    print('Running setUpModule')


def tearDownModule():
    print('Running tearDownModule')


class TestMyModule(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print('Running setUpClass')

    @classmethod
    def tearDownClass(cls):
        print('Running tearDownClass')

    def test_case_1(self):
        self.assertEqual(5+5, 10)

    def test_case_2(self):
        self.assertEqual(1+1, 2)

В этом примере мы добавили методы класса: setUpClass() и TearDownClass() в класс TestMyModule.

Если вы запустите тест, вы увидите следующий результат:

Running setUpModule
Running setUpClass
test_case_1(test_my_module.TestMyModule) ... ok
test_case_2(test_my_module.TestMyModule) ... ok
Running tearDownClass
Running tearDownModule

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

Фикстуры method-level

setUp() и TearDown() являются method-level фикстурами:

  • Функция setUp() выполняется перед каждым тестовым методом в тестовом классе.
  • TearDown() запускается после каждого тестового метода в тестовом классе.

Например:

import unittest


def setUpModule():
    print('Running setUpModule')


def tearDownModule():
    print('Running tearDownModule')


class TestMyModule(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print('Running setUpClass')

    @classmethod
    def tearDownClass(cls):
        print('Running tearDownClass')

    def setUp(self):
        print('')
        print('Running setUp')

    def tearDown(self):
        print('Running tearDown')

    def test_case_1(self):
        print('Running test_case_1')
        self.assertEqual(5+5, 10)

    def test_case_2(self):
        print('Running test_case_2')
        self.assertEqual(1+1, 2)

Ниже показаны результаты теста:

Running setUpModule
Running setUpClass
test_case_1(test_my_module.TestMyModule) ...
Running setUp
Running test_case_1
Running tearDown
ok
test_case_2(test_my_module.TestMyModule) ...
Running setUp
Running test_case_2
Running tearDown
ok
Running tearDownClass
Running tearDownModule

----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

В этом примере методы setUp() и TearDown() выполняются до и после каждого метода тестирования, включая test_case_1() и test_case_2().

Пример использования тестовых фикстур в Python

Сначала определите классы BankAccount и InsufficientFund в модуле bank_account.py:

class InsufficientFund(Exception):
    pass


class BankAccount:
    def __init__(self, balance: float) -> None:
        if balance < 0:
            raise ValueError('balance cannot be negative')
        self._balance = balance

    @property
    def balance(self) -> float:
        return self._balance

    def deposit(self, amount: float) -> None:
        if amount <= 0:
            raise ValueError('The amount must be positive')

        self._balance += amount

    def withdraw(self, amount: float) -> None:
        if amount <= 0:
            raise ValueError('The withdrawal amount must be more than 0')

        if amount > self._balance:
            raise InsufficientFund('Insufficient ammount for withdrawal')

        self._balance -= amount

Во-вторых, определите класс TestBankAccount в модуле test_bank_account.py:

import unittest

from bank_account import BankAccount


class TestBankAccount(unittest.TestCase):
    def test_deposit(self):
        self.bank_account = BankAccount(100)
        self.bank_account.deposit(100)
        self.assertEqual(self.bank_account.balance, 200)

    def test_withdraw(self):
        self.bank_account = BankAccount(100)
        self.bank_account.withdraw(50)
        self.assertEqual(self.bank_account.balance, 50)

Класс TestBankAccount имеет два метода тестирования:

  • test_deposit() – проверить метод депозита() банковского счета.
  • test_withdraw() – протестируйте метод вывода() банковского счета.

Оба метода создают новый экземпляр BankAccount. Это излишне.

Чтобы избежать избыточности, вы можете создать экземпляр класса BankAccount в методе setUp() и использовать его во всех методах тестирования:

import unittest

from bank_account import BankAccount


class TestBankAccount(unittest.TestCase):
    def setUp(self) -> None:
        self.bank_account = BankAccount(100)

    def test_deposit(self):
        self.bank_account.deposit(100)
        self.assertEqual(self.bank_account.balance, 200)

    def test_withdraw(self):
        self.bank_account.withdraw(50)
        self.assertEqual(self.bank_account.balance, 50)

В методе setUp():

  • Сначала создайте экземпляр класса BankAccount и присвойте его переменной экземпляра self.bank_account.
  • Затем используйте экземпляр self.bank_account в методах test_deposit() и test_withdraw().

При запуске методов тестирования test_deposit() и test_withdraw() метод setUp() запускается перед каждым методом тестирования.

Для метода test_deposit():

setUp()
test_deposit()

Для метода test_withdraw():

setUp()
test_withdraw()

Если вы запустите тест:

python -m unittest -v

Он выведет следующее:

test_deposit(test_bank_account.TestBankAccount) ... ok
test_withdraw(test_bank_account.TestBankAccount) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

Следующий код добавляет метод TearDown() в TestBankAccount:

import unittest

from bank_account import BankAccount, InsufficientFund


class TestBankAccount(unittest.TestCase):
    def setUp(self) -> None:
        self.bank_account = BankAccount(100)

    def test_deposit(self):
        self.bank_account.deposit(100)
        self.assertEqual(self.bank_account.balance, 200)

    def test_withdraw(self):
        self.bank_account.withdraw(50)
        self.assertEqual(self.bank_account.balance, 50)

    def tearDown(self) -> None:
        self.bank_account = None

Метод TearDown() присваивает None экземпляру self.bank_account.

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

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