Appearance
Skip - Пропуск тестов
Skip и Expected Failure
unittest
предоставляет возможность пропускать тесты или помечать их как ожидаемо проваленные.
@unittest.skip(reason)
: Позволяет пропустить выполнение теста.@unittest.skipIf(condition, reason)
: Позволяет пропустить выполнение теста в зависимости от условия.@unittest.skipUnless(condition, reason)
: Позволяет выполнить тест только если условие истинно.@unittest.expectedFailure
: Помечает тест как ожидаемо проваленный. Тест будет выполнен, но результат провала не приведет к общему провалу тестового набора.
python
import unittest
class MyClass:
def divide(self, a, b):
if b == 0:
raise ZeroDivisionError("Division by zero")
return a / b
class TestMyClass(unittest.TestCase):
def setUp(self):
self.my_object = MyClass()
@unittest.skip("Demonstrating skipping tests")
def test_add(self):
self.assertEqual(self.my_object.divide(2,2), 1)
@unittest.skipIf(1 == 1, "Condition is met, skip")
def test_subtract(self):
self.assertEqual(self.my_object.divide(2,2), 1)
@unittest.skipUnless(1 == 2, "Condition is not met, skip")
def test_multiply(self):
self.assertEqual(self.my_object.divide(2,2), 1)
@unittest.expectedFailure
def test_divide_by_zero(self):
with self.assertRaises(ZeroDivisionError):
self.my_object.divide(1, 0)
def test_divide(self):
self.assertEqual(self.my_object.divide(10, 2), 5)
if __name__ == '__main__':
unittest.main()
Mocking:
При тестировании модулей часто возникает необходимость изолировать тестируемый код от зависимостей, например, внешних API, баз данных или других модулей. Mocking
позволяет заменить эти зависимости "заглушками" (mocks), которые имитируют поведение реальных объектов. Python предоставляет библиотеку unittest.mock
для создания моков.
python
import unittest
from unittest.mock import patch
import requests
class DataFetcher:
"""
A class that fetches data from an external API.
"""
def get_data(self, url: str) -> dict:
"""
Fetches data from the given URL and returns it as a dictionary.
"""
response = requests.get(url)
response.raise_for_status() # Raises an exception for bad status codes
return response.json()
class TestDataFetcher(unittest.TestCase):
"""
Test case for the DataFetcher class.
"""
def setUp(self) -> None:
"""
Sets up the test fixture.
"""
self.data_fetcher = DataFetcher()
def tearDown(self) -> None:
"""
Tears down the test fixture.
"""
self.data_fetcher = None
@patch('requests.get')
def test_get_data_success(self, mock_get) -> None:
"""
Tests the get_data method with a successful response.
"""
mock_response = unittest.mock.Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"key": "value"}
mock_get.return_value = mock_response
url = "http://example.com/api/data"
data = self.data_fetcher.get_data(url)
mock_get.assert_called_once_with(url) # checks that `requests.get` was called with specified url.
self.assertEqual(data, {"key": "value"})
@patch('requests.get')
def test_get_data_error(self, mock_get) -> None:
"""
Tests the get_data method with an error response.
"""
mock_response = unittest.mock.Mock()
mock_response.status_code = 404
mock_get.return_value = mock_response
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("Not Found") # emulate error.
url = "http://example.com/api/data"
with self.assertRaises(requests.exceptions.HTTPError):
self.data_fetcher.get_data(url)
mock_get.assert_called_once_with(url)
if __name__ == '__main__':
unittest.main()
В этом примере мы используем декоратор @patch('requests.get')
для замены функции requests.get
моком. В методе test_get_data_success
мы создаем мок для объекта ответа (mock_response
) и устанавливаем его атрибуты status_code
и json
. Затем мы вызываем метод get_data
и проверяем, что функция requests.get
была вызвана с правильным URL и что возвращенные данные соответствуют ожидаемым.
В методе test_get_data_error
мы имитируем ошибочный ответ сервера и проверяем, что при этом выбрасывается исключение requests.exceptions.HTTPError
. Важно использовать mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("Not Found")
для имитации выброса исключения при вызове response.raise_for_status()
. Также проверяется, что mock_get
вызывается с ожидаемым аргументом.
Test Discovery:
Вместо того, чтобы явно добавлять тесты в TestSuite
, можно использовать автоматическое обнаружение тестов. unittest
предоставляет механизм для поиска и запуска всех тестов в указанной директории или модуле.
python
#file: my_tests.py
import unittest
class MyClass:
def add(self, a, b):
return a + b
class TestMyClass(unittest.TestCase):
def test_add_positive(self):
my_object = MyClass()
self.assertEqual(my_object.add(2, 3), 5)
def test_add_negative(self):
my_object = MyClass()
self.assertEqual(my_object.add(-2, -3), -5)
if __name__ == '__main__':
unittest.main()
Для запуска тестов, используя обнаружение тестов, выполните в терминале команду находясь в директории с файлом my_tests.py
:
bash
python -m unittest discover .
Эта команда автоматически найдет и запустит все тесты в текущей директории (.
). Вы можете указать конкретную директорию или шаблон имени файлов для поиска тестов.
Упражнения:
- Custom Assertions: Создайте класс
CustomAssertions
, который наследуется отunittest.TestCase
, и добавьте в него методыassertGreater(a, b)
иassertLess(a, b)
, которые проверяют, чтоa > b
иa < b
соответственно. Используйте эти методы в тестах для проверки сравнений чисел. - Mocking External Service: Создайте класс
PaymentProcessor
, который взаимодействует с внешним платежным сервисом (замокируйте этот сервис). Напишите тесты, которые проверяют успешную обработку платежа, отказ платежа (например, из-за недостатка средств) и обработку ошибок соединения с сервисом. - Test Suite Organization: Создайте несколько классов тестовых случаев для разных модулей вашего проекта. Организуйте их в
TestSuite
, используя различные способы добавления тестов (например,addTest
,addTests
,makeSuite
,TestLoader
). Запустите все тесты с помощьюTextTestRunner
. - HTML Test Runner: Используйте стороннюю библиотеку, такую как
HtmlTestRunner
, для генерации HTML-отчетов о результатах тестирования. Установите библиотеку (pip install html-testRunner
) и напишите скрипт, который запускает тесты и создает HTML-отчет. - Asyncio Testing: Если вы используете асинхронный код, напишите тесты, которые используют библиотеку
asyncio
иunittest
для тестирования асинхронных функций. Убедитесь, что вы корректно обрабатываете асинхронные операции и используетеasyncio.run
илиasyncio.get_event_loop().run_until_complete()
для запуска тестов.