Pytest
Теория
Виды тестирования
- Модульное: небольшой элемент/модуль
- Компонентное: проверка подсистем по отдельности
- Альфа/бета: в реальных условиях на настоящих данных в прод версии
- Комплексное: проверка связей интерфейсов между парами и группами компонентов
- Системное: поведение как в целом, так и в частности
- ПСИ: проверка удовлетворения системы требованиям
- Пилотное: опытная эксплуатация под тщательным контролем
Планирование тестирования
- Планирование тестирования - описывает все процессы. Понимание места тестирования
- операционный и организационный контекст
- Риски качества системы + ранжирование, понимание каждого возможностей тестирования для смягчения рисков
- Потребности временнЫх ресурсах
- План мероприятий по тестированию. Задачи, состав участников.
Важно Ожидание качества (численные критерии, предьявляемые перед началом) и Опыт качества (численное значение критериев после выполнения работ). Жизненный цикл системы = Жизненный цикл разработки + эксплуатации
- Подготовка к тестированию
- Обучение тестировщиков до нужного уровня
- Спроектировать систему тестирования (окружение, процедура, распределение задач, )
- Проведение тестирования
- Получение версии для тестирования
- Проведение тестов
Предпочтительнее алгоритм Дано-Ожидаемо-Проверка Лучше пофункциональное тестирование. Интегральные тесты хороши но не дают нужной детализации. Каждый тест должен возвращать состояние в начальное, они должны быть последовательно-независимыми
- Совершенствование
- Документирование тестирования
- Информирование о результатах
- При изменении контекста изменение процесса
Построение успешного процесса
- Что делает группа тестирования, когда применяет успешный процесс, и какие преимущества она получает.
- Нереалистичные ожидания со стороны руководства
- Получить согласие на изменение процесса сложнее самого изменения
- Процесс усовершенствования требует наличия плана
Элементы документации
- Точка тестирования:
- Итоговая цель тестирования:
- Краткосрочная цель и параметры тестирования:
- Документирование:
- Фиксирование версионности:
- Приоретизация тестирования:
- Параметры тестируемой подсистемы:
- Блоки:
- Функции в каждом блоке:
- Переменные каждой функции:
- Комбинированные ожидаемые результаты каждой функции от переменной:
Pytest
Соглашения об именованиях
Имя файла должна начинаться с test_
Функция тестирования должна начинаться с test_
Классы: Test<Something>
Запуск тестов
pytest
по-умолчанию без параметров - все файлы test_ в текущей папке и поддиректориях
pytest test_classes.py::TestEquality Запуск конкретного класса pytest test_classes.py::TestEquality::test_equality Запуск конкретного метода в конкретном тестклассе
@pytest.mark.skip() или @pytest.mark.skipif() - декораторы для пропуска теста
test_file.py использование конкретного файла
dir конкретная директория
-v расширенный вывод
--tb=no включение/отключение traceback, по-умолчанию включено
-k Маркер
-k equality все классы/тесты с именем включающим слово equality
-k "equality and not equality_fail" все классы/тесты с именем включающим слово equality и без equality_fail
-k "(dict or ids) and not TestEquality"
--setup-show показывает последовательность применения fixture и самого теста
--fixtures -v расположение файла fixtures
--fixtures-per-test отдельно использовать fixtures для каждого теста
Возможные статусы:
PASSED (.), FAILED (F), SKIPPED (s),
XFAIL (x), Тест ожидался провальным (был обернут декоратором @pytest.mark.xfail()), и провалился
XPASS (X), Тест ожидался провальным (был обернут декоратором @pytest.mark.xfail()), но успешно
ERROR (E) При выполнении теста исключение
Пример полного файла (test_one.py):
def test_passing():
assert (1, 2, 3) == (1, 2, 3)
запуск: pytest test_one.py
Примеры функций тестов
Изменение функции проверки
def assert_identical(c1: Card, c2: Card):
__tracebackhide__ = True
assert c1 == c2
if c1.id != c2.id:
pytest.fail(f'id\'s don\'t match. {c1.id} != {c2.id}')
Тестирование ожидаемого исключения
def test_no_path_raises():
with pytest.raises(TypeError):
cards.CardsDB()
Тестирование ожидаемого исключения с конкретным текстом через regex
def test_raises_with_info():
match_regex = "missing 1 .* positional argument"
with pytest.raises(TypeError, match=match_regex):
cards.CardsDB()
Тестирование ожидаемого исключения с конкретным текстом через проверку наличия текста
def test_raises_with_info_alt():
with pytest.raises(TypeError) as exc_info:
cards.CardsDB()
expected = "missing 1 required positional argument"
assert expected in str(exc_info.value)
Fixtures
функции, запускающиеся до выполнения тестов (и/или после), для перевода системы в нужный контекст.
При ошибке в fixture генерится Error
@pytest.fixture() - запуск при каждом обращении
@pytest.fixture(scope="module") - один запуск на уровне модуля
scope='function' по умолчанию
scope='class' один запуск на уровне класса
scope='module'
scope='package' - в случае определения fixture в файле conftest.py
scope='session' - в случае определения fixture в файле conftest.py
Запуск до исполнения
import pytest
@pytest.fixture()
def some_data():
"""Return answer to ultimate question."""
return 42
def test_some_data(some_data):
"""Use fixture return value in a test."""
assert some_data == 42
Пример запуска с итераторами:
@pytest.fixture()
def cards_db():
# setup part
with TemporaryDirectory() as db_dir:
db_path = Path(db_dir)
db = cards.CardsDB(db_path)
# end setup part, return db object
yield db
# closing db after testing
db.close()
def test_empty(cards_db):
# in cards_db - db object, we can use it
assert cards_db.count() == 0
Fixtures можно вынести в отдельный файл conftest.py В директории теста или в родительской директории
pytest --fixtures -v расположение файла
#ch3/a/conftest.py
from pathlib import Path
from tempfile import TemporaryDirectory
import cards
import pytest
@pytest.fixture(scope="session")
def cards_db():
"""CardsDB object connected to a temporary database"""
with TemporaryDirectory() as db_dir:
db_path = Path(db_dir)
db = cards.CardsDB(db_path)
yield db
db.close()
#ch3/a/test_count.py
import cards
def test_empty(cards_db):
assert cards_db.count() == 0
def test_two(cards_db):
cards_db.add_card(cards.Card("first"))
cards_db.add_card(cards.Card("second"))
assert cards_db.count() == 2
Взаимозапуск fixtures
@pytest.fixture(scope="session")
def db():
"""CardsDB object connected to a temporary database"""
with TemporaryDirectory() as db_dir:
db_path = Path(db_dir)
db_ = cards.CardsDB(db_path)
yield db_
db_.close()
@pytest.fixture(scope="function")
def cards_db(db):
"""CardsDB object that's empty"""
db.delete_all()
return db
Множественное использование fixtures
#ch3/c/conftest.py
@pytest.fixture(scope="function")
def non_empty_db(cards_db, some_cards):
...
No comments to display
No comments to display