Master Pytest: From Basics to Advanced Fixtures and Allure Reporting
This comprehensive guide walks you through Pytest fundamentals, basic usage, fixture mechanisms, conftest configuration, and advanced features such as Allure report beautification, parameterized data‑driven testing, and YAML integration, providing practical code examples for Python test automation.
We previously covered Python's built‑in unittest framework, which has certain limitations. This article introduces the third‑party framework Pytest, which retains unittest syntax while offering many optimizations.
We will cover Pytest from the following angles:
Pytest basic introduction
Pytest basic usage
Pytest advanced content
Pytest Basic Introduction
First, a brief overview of Pytest and related concepts.
Unit Test Framework
Testing generally includes four types:
Unit testing: testing the smallest software unit (module) for correctness.
Integration testing: testing combined modules, focusing on interfaces.
System testing: testing the whole system, including functionality, performance, and environment.
Acceptance testing: testing against contract‑defined criteria to decide system acceptance.
This article focuses on unit testing:
Python: UnitTest and Pytest are used for unit test automation; Pytest is now mainstream.
Java: TestNG and JUnit are used; TestNG is mainstream.
The main functions of a unit‑test framework are:
Discover test cases
Execute test cases
Determine test results
Generate test reports
Framework Basic Introduction
Key points about Pytest:
Pytest is a mature unit‑test framework with flexibility and simplicity.
It has strong compatibility and ecosystem, integrating with Selenium, Requests, Appium, etc.
It provides better reporting, supporting custom Allure reports and Jenkins CI.
Common Pytest plugins:
pytest‑html: generate HTML reports
pytest‑xdist: multi‑threaded execution
pytest‑ordering: change test execution order
pytest‑rerunfailures: rerun failed tests
allure‑pytest: generate attractive Allure reports
Install all plugins at once:
# Create a file requestment.txt with plugin names
pytest-html
pytest-xdist
pytest-ordering
pytest-rerunfailures
# Install them
pip install -r requestment.txtPytest Basic Usage
Default test case naming rules:
# Test modules must be placed in a testcases folder and start or end with "test_"
# Example module names
test_demo1.py
demo2_test.py
# Test classes must start with "Test" and cannot have an __init__ method
class TestDemo1:
pass
class TestLogin:
pass
# Test methods must start with "test_"
def test_demo1(self):
pass
def test_demo2(self):
pass
# Example test case
class TestDemo:
def test_demo1(self):
print("Test case 1")
def test_demo2(self):
print("Test case 2")Running tests:
# pytest.ini configuration (place in project root)
[pytest]
addopts = -vs
testpaths = ./testcases
python_files = test_*.py
python_classes = Test*
python_functions = test_*
markers =
smoke: smoke tests
product_manage: product management tests
# Command line examples
pytest -vs # verbose and show prints
pytest -vs -n=2 # run with 2 parallel workers (requires pytest‑xdist)
pytest -vs --reruns=2 # rerun failed tests (requires pytest‑rerunfailures)
pytest -vs -x # stop after first failure
pytest -vs --maxfail=2 # stop after two failures
pytest -vs --html ./reports/result.html # generate HTML report (requires pytest‑html)
pytest -vs -k "keyword" # run tests whose names contain keyword
pytest -vs -k "a or b" # run tests matching a or b
pytest -vs -k "a and b" # run tests matching both a and b
pytest -vs -m smoke # run tests marked as smokeSkipping tests (same as unittest):
# Skip without reason
@pytest.mark.skip(reason="No reason")
def test_demo1(self):
print("Skipped")
# Skip conditionally
workage2 = 5
workage3 = 20
@pytest.mark.skipif(workage2 < 10, reason="Experience less than 10 years")
def test_demo2(self):
print("Skipped due to experience")
@pytest.mark.skipif(workage3 < 10, reason="Experience less than 10 years")
def test_demo3(self):
print("Executed")Pytest Setup and Teardown
Understanding fixtures for pre‑ and post‑actions at different scopes:
Function scope – runs before and after each test function.
Class scope – runs once before and after all methods in a class.
Module scope – runs before and after all tests in a module.
# Function‑level fixture
@pytest.fixture(scope="function")
def exe_database_sql():
print("Execute SQL query")
yield
print("Close DB connection")
# Class‑level fixture
@pytest.fixture(scope="class")
def exe_database_sql():
print("Execute SQL query")
yield
print("Close DB connection")
# Session‑level fixture
@pytest.fixture(scope="session")
def exe_database_sql():
print("Execute SQL query")
yield
print("Close DB connection")Using fixtures automatically:
# Auto‑use fixture
@pytest.fixture(scope="function", autouse=True)
def exe_database_sql():
print("Execute SQL query")
yield
print("Close DB connection")Parameterizing fixtures:
# Parameterized fixture with request
@pytest.fixture(scope="function", params=["val1", "val2"], ids=["1", "2"])
def exe_database_sql(request):
print("Execute SQL query")
yield request.param
print("Close DB connection")conftest.py
The conftest.py file stores shared fixtures. Its location determines the fixture scope:
Root‑level conftest.py – fixtures available to all tests.
Subdirectory conftest.py – fixtures limited to that directory.
# conftest.py at project root
import pytest
@pytest.fixture(scope="function", name="exe_database_sql_name")
def exe_database_sql():
print("Run before all methods")
yield
print("Run after all methods")Fixture usage in tests (no import needed):
# test_demo1.py
import pytest
class TestDemo1:
def test_1(self, exe_database_sql_name):
print("Login success" + exe_database_sql_name)Pytest Advanced Content
Allure Report Beautification
Allure provides a flexible, lightweight multi‑language test report with a web UI.
# Install Allure command‑line tool and set PATH
# Install pytest plugin
pip install allure-pytest
# Generate Allure JSON files
pytest --alluredir=./temps --clean-alluredir
# Generate HTML report
allure generate ./temps -o ./reports --cleanParametrize Data‑Driven Testing
Use @pytest.mark.parametrize to drive tests with multiple data sets.
# Single parameter list
@pytest.mark.parametrize('caseinfo', ['A', 'B', 'C'])
def test_01(self, caseinfo):
print("Token:" + caseinfo)
# Multiple parameters
@pytest.mark.parametrize('arg1,arg2', [['A1','A2'], ['B1','B2']])
def test_01(self, arg1, arg2):
print("Token:" + str(arg1) + " " + str(arg2))Combine with YAML files for external data:
# read_yaml function (requires pyyaml)
import os, yaml
def get_obj_path():
return os.path.dirname(__file__).split('common')[0]
def read_yaml(yamlPath):
with open(get_obj_path() + yamlPath, mode='r', encoding='utf-8') as f:
return yaml.load(f, Loader=yaml.FullLoader)
# Use in parametrize
@pytest.mark.parametrize('caseinfo', read_yaml('testcase/user_manage/get_token.yaml'))
def test_01(self, caseinfo):
print("Token:" + caseinfo)
print("Name:" + caseinfo['name'])
print("Method:" + caseinfo['request']['method'])
print("URL:" + caseinfo['request']['url'])
print("Data:" + caseinfo['request']['data'])Overall fixture execution order:
fixture_session > fixture_class > setup_class > fixture_function > setup
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
