What are Pytest Hooks?
Hooks are a key part of Pytest’s plugin system used to extend Pytest’s functionality.
At their core, Pytest Hooks are gateway points, allowing you to inject logic at specific stages of the test execution process to modify or extend the behaviour of tests based on test events.
Pytest offers a variety of hooks, each designed for different purposes and stages of the test cycle.
Types of Pytest Hooks
Pytest Hooks are categorized based on the stage of the testing process they’re involved in.
Bootstrapping Hooks
-
Called at the very beginning and end of the Pytest test run. Crucial for setting up and tearing down configurations or environments that are needed for the entire test suite.
-
Initialization Hooks
-
These hooks come into play after bootstrapping and are instrumental for tasks like adding command-line options or integrating new plugins. They set the stage for a customized testing environment.
-
Collection Hooks
-
These hooks deal with discovering and organizing test cases. They give you the power to influence how Pytest collects tests, allowing you to add, modify, or skip tests based on custom criteria.
-
Test running (runtest) hooks
-
These hooks offer a way to customize test execution. They’re incredibly versatile, enabling actions before, during, and after a test is run. This can range from setting up test data to cleaning up resources after a test.
Reporting Hooks
- These hooks are all about how test results are processed and presented. They provide a means to customize the output, create custom reports, or even integrate with external systems for reporting purposes.
Debugging/Interaction Hooks
- These hooks are invaluable for debugging. They come into play when tests fail or when you need to drop into an interactive session. They can help in inspecting the state of a test at various points or managing breakpoints..
Example - pytest_sessionstart
and pytest_sessionfinish
Hooks
Let’s look at how to use 2 simple hooks - pytest_sessionstart
and pytest_sessionfinish
- to perform some custom actions at the start and end of the test session.
In your conftest.py
file, let’s define these hooks.
import pytest@pytest.hookimpl()def pytest_sessionstart(session): print("Hello from \`pytest_sessionstart\` hook!")@pytest.hookimpl()def pytest_sessionfinish(session, exitstatus): print("Hello from \`pytest_sessionfinish\` hook!") print(f"Exit status: {exitstatus}")
You’ll notice that I’ve used the @pytest.hookimpl()
decorator to mark these functions as hook implementations. This is a way of telling Pytest that these functions are implementations of hooks.
Let’s also define a simple test for the sake of this example.
./tests/example1/test_example1.py
def test_example1_pass(): print("Running test1") assert True
Ordering of Pytest Hooks
Not only do Pytest Hooks allow us cool customization options, but also control the order in which these are executed.
You can do this via the @pytest.hookimpl
decorator.
The @pytest.hookimpl
decorator is used to mark a function as a hook implementation.
- Execution as Early as Possible
By usingtryfirst=True
as an argument, you can make a hook implementation execute earlier than others.
@pytest.hookimpl(tryfirst=True)
-
Execution as Late as Possible
Alternatively,trylast=True
ensures the hook implementation executes later in the sequence. -
Hook Wrappers
Thehookwrapper=True
argument creates a hook that wraps around all others. It can execute code both before and after the standard hooks.
Plugins vs Hooks
As you learnt, hooks are predefined points in the framework’s execution at which you can insert your own code to alter or enhance the testing process.
Plugins, on the other hand, are external or internal extensions that utilize these hooks to integrate additional features into Pytest.
plugins are a way to package and distribute custom hooks and fixtures, making them reusable across different projects
Fixtures vs Hooks
Pytest Fixtures are reusable pieces of code that you can invoke in your tests to set up a specific state or environment before the test runs and optionally clean up after the test is done.
These important operations are commonly referred to as setup and teardown.
While fixtures primarily focus on setting up and tearing down test conditions, hooks give you the leverage to customize the testing process itself.
Can Pytest Hooks be Defined Outside conftest.py
?
Defining your hooks in conftest.py
is indeed common practice.
However, you can absolutely define Pytest hooks outside of conftest.py
.
You can define hooks in any Python file and then register them using the pytest.hookimpl()
decorator.
How To Access All Collected Test Reports in Pytest?
This is a question asked by a fellow developer on StackOverflow who wanted to send logs over to Datadog.
Now this is a great example of the use case of reporting hooks, for example, pytest_terminal_summary
.