Appearance
TestSuite
и TestRunner
Основные концепции
Тестовый случай (TestCase
) — это класс, который наследуется от unittest.TestCase
. В этом классе определяются методы, которые начинаются с префикса test_
, каждый из которых представляет собой отдельный тест.
Тестовый набор (TestSuite
) — это коллекция тестовых случаев или других тестовых наборов. Используется для группировки тестов и управления их порядком выполнения.
Тестовый исполнитель (TestRunner
) — это компонент, который управляет выполнением тестов и предоставляет результаты. TextTestRunner
— это стандартный текстовый тестовый исполнитель, который выводит результаты тестов в консоль.
testSuite
- Тестовый набор
testSuite
— это коллекция тестов, которые можно выполнять вместе. Это полезно, когда нужно сгруппировать тесты по определенным критериям, например, по функциональности или модулям.
Пример объединения тестовых классов
python
import unittest
class TestMathOperations(unittest.TestCase):
"""Тестирование математических операций."""
def test_addition(self) -> None:
"""Тестирование операции сложения."""
self.assertEqual(1 + 1, 2)
class TestStringMethods(unittest.TestCase):
"""Тестирование строковых методов."""
def test_upper(self) -> None:
"""Тестирование метода upper()."""
self.assertEqual('foo'.upper(), 'FOO')
def test_lower(self) -> None:
"""Тестирование метода lower()."""
self.assertEqual('foo'.lower(), 'foo')
def get_suite() -> unittest.TestSuite:
"""Создание TestSuite, включающей все тесты."""
suite = unittest.TestSuite()
case = unittest.TestLoader()
suite_1 = case.loadTestsFromTestCase(TestMathOperations)
suite.addTest(suite_1)
suite_2 = case.loadTestsFromTestCase(TestStringMethods)
suite.addTest(suite_2)
return suite
runner = unittest.TextTestRunner(verbosity=2)
runner.run(get_suite())
Пример объединения отдельных тестов
python
import unittest
def add(a: int, b: int) -> int:
"""Addition function"""
return a + b
def multiply(a: int, b: int) -> int:
"""Multiply function"""
return a * b
class TestMathOperations(unittest.TestCase):
"""Tests for math operations"""
def test_add(self) -> None:
"""Test that the add function works correctly"""
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(-1, -1), -2)
def test_multiply(self) -> None:
"""Test that the multiply function works correctly"""
self.assertEqual(multiply(3, 2), 6)
self.assertEqual(multiply(-1, 1), -1)
self.assertEqual(multiply(-1, -1), 1)
# Создаем TestSuite
suite = unittest.TestSuite()
suite.addTest(TestMathOperations('test_add'))
suite.addTest(TestMathOperations('test_multiply'))
# Создаем TextTestRunner и запускаем тесты
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
TextTestRunner
и verbosity
TextTestRunner
— это один из способов запуска тестов, который выводит результаты в текстовом виде. Параметр verbosity
(многословие) управляет уровнем детализации выводимой информации.
verbosity=0
: только количество ошибок и пропущенных тестов.verbosity=1
(по умолчанию): выводит краткую информацию о пройденных и не пройденных тестах, и общее время выполнения.verbosity=2
: выводит детальную информацию о каждом тесте.
Пример с разным уровнем verbosity
python
import unittest
class TestVerbosity(unittest.TestCase):
"""Tests to demonstrate verbosity"""
def test_success(self) -> None:
"""A test that should pass"""
self.assertEqual(1 + 1, 2)
def test_failure(self) -> None:
"""A test that should fail"""
self.assertEqual(1 + 1, 3)
# Запуск с verbosity=0
runner = unittest.TextTestRunner(verbosity=0)
suite = unittest.TestLoader().loadTestsFromTestCase(TestVerbosity)
runner.run(suite)
# Запуск с verbosity=1
runner = unittest.TextTestRunner(verbosity=1)
suite = unittest.TestLoader().loadTestsFromTestCase(TestVerbosity)
runner.run(suite)
# Запуск с verbosity=2
runner = unittest.TextTestRunner(verbosity=2)
suite = unittest.TestLoader().loadTestsFromTestCase(TestVerbosity)
runner.run(suite)
Упражнения
Упражнение 1: Тестирование функции деления
Создайте функцию divide(a: int, b: int) -> float
, которая делит одно число на другое, и напишите тесты для этой функции, включая случай деления на ноль.
Упражнение 2: Использование setUp
и tearDown
Напишите класс тестов, в котором используются методы setUp
и tearDown
для инициализации и очистки ресурсов перед и после каждого теста.
Упражнение 3: Создание TestSuite
Создайте несколько классов тестов и объедините их в TestSuite
. Запустите TestSuite
с помощью TextTestRunner
.
Упражнение 4: Тестирование исключений
Напишите тесты для функции, которая должна генерировать исключения в определенных случаях. Используйте метод assertRaises
.
Упражнение 5: Параметризация тестов
Используйте метод subTest
для параметризации тестов. Например, напишите один тест для проверки нескольких пар значений для функции add
.
Упражнение 6: Использование внешних данных
Напишите тесты, которые используют внешние данные (например, из файла или базы данных) для проверки функциональности вашего кода.
Упражнение 7: Настройка verbosity
Экспериментируйте с разными значениями verbosity
в TextTestRunner
и наблюдайте, как меняется вывод результатов тестирования.
Упражнение 1: Тестирование функции factorial
Напишите тесты для функции factorial
, которая вычисляет факториал числа.
python
def factorial(n: int) -> int:
"""Вычисление факториала числа n."""
if n == 0:
return 1
return n * factorial(n - 1)
Упражнение 2: Тестирование класса Stack
Создайте класс Stack
с методами push
, pop
, is_empty
и напишите тесты для каждого метода.
python
class Stack:
"""Стек на основе списка."""
def __init__(self) -> None:
self.items: list = []
def push(self, item: int) -> None:
"""Добавление элемента в стек."""
self.items.append(item)
def pop(self) -> int:
"""Удаление и возврат верхнего элемента стека."""
if not self.is_empty():
return self.items.pop()
raise IndexError("pop from empty stack")
def is_empty(self) -> bool:
"""Проверка, пуст ли стек."""
return len(self.items) == 0
Упражнение 3: Тестирование исключений
Напишите тесты для функции divide
, которая делит два числа и вызывает ValueError
, если делитель равен нулю.
python
def divide(a: int, b: int) -> float:
"""Деление a на b."""
if b == 0:
raise ValueError("Division by zero")
return a / b
Упражнение 4: Тестирование класса Rectangle
Создайте класс Rectangle
с методами area
и perimeter
и напишите тесты для каждого метода.
python
class Rectangle:
"""Прямоугольник с заданными шириной и высотой."""
def __init__(self, width: int, height: int) -> None:
self.width = width
self.height = height
def area(self) -> int:
"""Вычисление площади прямоугольника."""
return self.width * self.height
def perimeter(self) -> int:
"""Вычисление периметра прямоугольника."""
return 2 * (self.width + self.height)
Упражнение 5: Тестирование функции find_max
Напишите тесты для функции find_max
, которая находит максимальное значение в списке чисел.
python
def find_max(numbers: list[int]) -> int:
"""Поиск максимального значения в списке numbers."""
if not numbers:
raise ValueError("List is empty")
return max(numbers)
Упражнение 6: Тестирование функции is_palindrome
Напишите тесты для функции is_palindrome
, которая проверяет, является ли строка палиндромом.
python
def is_palindrome(s: str) -> bool:
"""Проверка, является ли строка s палиндромом."""
return s == s[::-1]
Упражнение 7: Тестирование функции flatten
Напишите тесты для функции flatten
, которая преобразует вложенный список в плоский.
python
def flatten(lst: list) -> list:
"""Преобразование вложенного списка в плоский."""
result = []
for item in lst:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result