Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Comprehensive Guide to Pytest and Jenkins Integration

Tech May 8 3

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 assert keyword 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_*.py or *_test.py.
  • Test Functions: Functions starting with test_.
  • Test Classes: Classes starting with Test (without an __init__ method) containing methods starting with test_.

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:

  1. 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
  1. 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
  1. 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:

  1. Download Allure from its GitHub repository.
  2. Extract the archive and set the ALLURE_HOME environment variable to the extracted directory.
  3. 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

  1. Navigate to Manage Jenkins > Manage Nodes and Clouds > New Node.
  2. Enter a name for the node and select Permanent Agent.
  3. Configure the node details, including the number of executors, remote working directory, and labels.
  4. Choose the launch method (e.g., Launch agent by connecting it to the master).
  5. Download the slave-agent.jnlp file and run it on the agent machine, or set it up as a system service.

Generating Allure Reports in Jenkins

  1. Install the Allure Jenkins Plugin in Jenkins.
  2. Configure the Allure Commandline tool in Manage Jenkins > Global Tool Configuration, pointing to the Allure installation directory.
  3. In your Jenkins job configuration, add a Post-build Action of type Publish Allure Report.
  4. Specify the Results directory where the --alluredir output from Pytest is stored (e.g., allure_results).

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.