Python Pytest
Links: 108 Python Index
Pytest¶
- In pytest tests are written as functions.
- You want all of you tests to be independent of each other so that they can be run independently.
Requirements for pytest
to find the tests. If the naming convention is not met then pytest
won't be able to find the tests.
- The file should start with
test_
or end in_test
. - The functions must be prefixed with
test_
. - It is a general convention to keep all the tests within the
tests
folder but this is not mandatory.
-
Just running
pytest
will execute all the tests.- Executing a specific test file:
pytest tests/test_specific.py
- Executing a specific function in a test file:
pytest tests/test_specific.py::function_name
- Executing a specific test file:
-
Commands:
- Running in verbose mode
pytest -v
- If you have a lot of tests to run and want less output
pytest -q
- Show actual values of local variables in the traceback
pytest -l
- Running in verbose mode
-
By default pytest only prints something when the tests fail.
- But if we want pytest to print something then we use
pytest -s
- But if we want pytest to print something then we use
-
We can have multiple asserts in a single test function and they will be considered as single test.
- Each function is a single test irrespective of the assert statements inside it.
-
Each test is quite small and self-contained.
- This is common you’ll see long function names and NOT a lot going on within a function.
- The idea is that the function should describe what the test is trying to test.
- This serves mainly to keep your tests isolated from each other, so if something breaks, you know exactly where the problem is.
- A nice side effect is that the labelling is much better in the output.
- This is common you’ll see long function names and NOT a lot going on within a function.
It is always a good idea that after passing your tests you make them fail intentionally.
Fixtures¶
- Fixtures are functions which give data to other functions.
- This concept is simple yet most powerful in pytest framework.
- These fixtures run before and then execution of test function follows.
- A function can declared as a fixture by,
- So, fixture function name is passed as arguments for corresponding test functions and used where ever needed.
- Here, in fixture function, string variable is returned.
- This is accesses by rest of the test functions , instead of repeating the same code again and again.
def test_upper(input_value):
assert input_value.upper() == "PYTHON"
def test_isalpha(input_value):
assert input_value.isalpha() == True
The major advantage of using fixtures reduces the code complexity, length of code and cost as well.
For example, while establishing database connection, we can make use of these fixtures to code data regarding setting up connection in one place and make use of it where ever needed.
-
In
pytest
, fixtures are modular.- Being modular means that fixtures can be imported, can import other modules, and they can depend on and import other fixtures.
- If we want to make a fixture available for your whole project without having to import it, a special configuration module called
conftest.py
will allow you to do that.
-
Another interesting use case for fixtures and
conftest.py
is in guarding access to resources.- Imagine that you’ve written a test suite for code that deals with API calls.
- You want to ensure that the test suite doesn’t make any real network calls even if someone accidentally writes a test that does so.
pytest
provides amonkeypatch
fixture to replace values and behaviours, which we can use to great effect
# conftest.py
import pytest
import requests
@pytest.fixture(autouse=True)
def disable_network_calls(monkeypatch):
def stunted_get():
raise RuntimeError("Network access not allowed during testing!")
monkeypatch.setattr(requests, "get", lambda *args, **kwargs: stunted_get())
- By placing
disable_network_calls()
inconftest.py
and adding theautouse=True
option, you ensure that network calls will be disabled in every test across the suite.- Any test that executes code calling
requests.get()
will raise aRuntimeError
indicating that an unexpected network call would have occurred.
- Any test that executes code calling
Different ways of running tests¶
- Run all tests:
pytest
- Run tests in a module:
pytest test_mod.py
- Run tests in a directory:
pytest testing/
- Run a specific test in a module:
pytest test_mod.py::test_func
Using marker expressions¶
- Run tests with marker expressions:
pytest -m slow
- Will run all tests which are decorated with the
@pytest.mark.slow
decorator - Skipping tests:
@pytest.mark.skip
- Will run all tests which are decorated with the
- For using custom markers we need to define them in
pytest.ini
file.
# sample code
import pytest
@pytest.mark.login
def test_regression():
print("Test_regression")
@pytest.mark.login
def test_sanity():
print("Test_sanity")
@pytest.mark.login
def test_release():
print("Test_release")
@pytest.mark.settings
def test_api():
print("Test_api")
@pytest.mark.login
@pytest.mark.settings
def test_api1():
print("Test_api1")
References¶
- Effective Python Testing With Pytest – Real Python
- PyTest • REST API Integration Testing with Python - YouTube
- Pytest Unit Testing Tutorial • How to test your Python code - YouTube
Last updated: 2023-01-21