Comprehensive Guide to Pytest and Jenkins Integration
Introduction to Pytest
Pytest is a powerful and flexible testing framework for Python, built upon the foundation of the standard unittest module and the older nose framework. It offers several advantages, including automatic discovery of test modules and methods, simple assertion syntax using plain assert statements, and a robust system for managing test setup and teardown through fixtures.
Key features of Pytest include:
- Automatic Test Discovery: Pytest automatically finds and runs tests based on naming conventions.
- Simple Assertions: Utilizes Python's built-in
assertkeyword for clear and readable test conditions. - Fixtures: A powerful mechanism for managing test dependencies, setup, and teardown at various scopes (session, module, class, function).
- Rich Plugin Ecosystem: A vast collection of plugins, such as
allure, to extend functionality.
Installation
To install Pytest, use the following pip command:
pip install pytest
For generating HTML reports, install the pytest-html plugin:
pip install pytest-html
You can explore the extensive list of available plugins at the Pytest Plugin Compatibility website.
Test Discovery Rules
Pytest automatically discovers test files and methods based on specific naming conventions:
- Test Files: Files matching the pattern
test_*.pyor*_test.py. - Test Functions: Functions starting with
test_. - Test Classes: Classes starting with
Test(without an__init__method) containing methods starting withtest_.
Using Markers
Markers allow you to categorize tests and selectively run them. You can define custom markers to group tests by functionality, priority, or any other criteria.
Registering Markers
Markers can be registered in a pytest.ini file:
[pytest]
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
serial: marks tests that must run sequentially
Alternatively, markers can be registered in conftest.py:
def pytest_configure(config):
config.addinivalue_line("markers", "smoke1: mark tests for smoke testing")
config.addinivalue_line("markers", "demo1: example marker")
Applying Markers
Markers can be applied to individual tests, entire test classes, or entire modules.
Individual Tests:
@pytest.mark.slow
@pytest.mark.serial
def test_example():
assert True
Test Classes:
class TestClass:
pytestmark = pytest.mark.slow
def test_method_one(self):
assert True
def test_method_two(self):
assert False
Modules:
import pytest
pytestmark = pytest.mark.slow
def test_function():
assert True
Running Tests from the Command Line
After installation, the pytest command becomes available. You can run all discovered tests or filter them using markers:
# Run all tests
pytest
# Run tests with a specific marker
pytest -m slow -v
# Run tests from a specific file
pytest test_module.py
# Run tests matching a keyword expression
pytest -k "test_login"
Fixtures
Fixtures are functions that provide a fixed baseline for tests. They can be used for setup and teardown operations.
Defining a Fixture:
@pytest.fixture
def database_connection():
# Setup: connect to the database
conn = create_connection()
yield conn # The fixture's return value is passed to the test
# Teardown: close the connection
conn.close()
Using a Fixture:
There are three primary ways to use a fixture:
- As a function argument: The fixture name is past as a argument to the test function.
def test_query_database(database_connection):
result = database_connection.execute("SELECT * FROM users")
assert result is not None
- Using
usefixtures: The fixture is applied to an entire class or module.
@pytest.mark.usefixtures("database_connection")
class TestDatabaseOperations:
def test_insert_user(self):
# database_connection is available here
pass
- Autouse: The fixture is automatically used for all tests in its scope when
autouse=True.
@pytest.fixture(autouse=True)
def clear_cache():
clear_cache_function()
yield
# Teardown for cache clearing
Parameterization
Pytest allows you to run a single test function with multiple sets of arguments using the parametrize marker.
Single Parameter:
@pytest.mark.parametrize("input_value, expected_output", [
(1, 2),
(3, 4),
(5, 6)
])
def test_add_one(input_value, expected_output):
assert input_value + 1 == expected_output
Multiple Parameters:
@pytest.mark.parametrize("a, b, expected_sum", [
(1, 2, 3),
(10, 20, 30),
(5.5, 4.5, 10)
])
def test_addition(a, b, expected_sum):
assert a + b == expected_sum
Combining Parameterizations (Cartesian Product):
@pytest.mark.parametrize("x", [1, 2])
@pytest.mark.parametrize("y", [3, 4])
def test_cartesian_product(x, y):
assert x * y in [3, 4, 6, 8]
Rerunning Failed Tests
The rerunfailures plugin allows you to automatically rerun tests that have failed.
Installation:
pip install pytest-rerunfailures
Usage:
# Rerun failed tests up to 3 times
pytest --reruns 3
# Rerun failed tests with a 5-second delay between reruns
pytest --reruns 3 --reruns-delay 5
Generating Test Reports
Pytest can generate various types of reports to help analyze test results.
HTML Reports
Install the pytest-html plugin and use the --html option:
pytest --html=reports/test_report.html
Allure Reports
Allure is a powerful reporting tool that provides detailed and interactive test reports.
Installation:
- Download Allure from its GitHub repository.
- Extract the archive and set the
ALLURE_HOMEenvironment variable to the extracted directory. - Install the Pytest plugin:
pip install allure-pytest.
Generating Reports:
# Generate Allure results
pytest --alluredir=allure_results
# Serve the report
allure serve allure_results
Integrating Pytest with Jenkins
Jenkins can be configured to run Pytest tests and generate reports, including Allure reports.
Jenkins Master/Slave Architecture
To distribute the load of test execution, Jenkins uses a master/slave architecture:
- Master: The main Jenkins server that manages jobs and distributes tasks.
- Slave (Agent):strong> Machines that execute the tasks assigned by the master.
Configuring a Jenkins Slave
- Navigate to Manage Jenkins > Manage Nodes and Clouds > New Node.
- Enter a name for the node and select Permanent Agent.
- Configure the node details, including the number of executors, remote working directory, and labels.
- Choose the launch method (e.g., Launch agent by connecting it to the master).
- Download the
slave-agent.jnlpfile and run it on the agent machine, or set it up as a system service.
Generating Allure Reports in Jenkins
- Install the Allure Jenkins Plugin in Jenkins.
- Configure the Allure Commandline tool in Manage Jenkins > Global Tool Configuration, pointing to the Allure installation directory.
- In your Jenkins job configuration, add a Post-build Action of type Publish Allure Report.
- Specify the Results directory where the
--allurediroutput from Pytest is stored (e.g.,allure_results).