Pytest is a popular testing framework in Python that allows for simple unit tests as well as complex functional testing. It follows a no-boilerplate philosophy, which makes your test code concise and easy to read. With pytest
, you can ensure the code behaves as expected and make code changes confidently.
Key Features:
- Simple to start: Write simple Python functions with assert statements to create tests.
- Powerful and Extensible: Supports fixtures, parameterized testing, and has numerous plugins.
- Detailed Info on Failures: Provides detailed information on failures that help quickly introspect and fix issues.
- Modularity: Write modular tests with fixtures.
- Skip and xfail: Mark some tests to skip or to be expected to fail.
Basic Usage:
- Installation
Installpytest
using pip:
pip install pytest
- Writing a Basic Test
Tests are simple Python functions that use assert statements.
def test_addition():
assert 1 + 1 == 2
- Running the Test
Run tests in a file.
pytest test_file_name.py
Or run all tests found in a directory.
pytest testing_directory/
Fixtures for Setup Code:
pytest
uses fixtures for setup code. Fixtures are functions that create data or context needed for tests.
import pytest
@pytest.fixture
def sample_dict():
return {"Python": 3, "pytest": 4}
def test_python_version(sample_dict):
assert sample_dict["Python"] == 3
Here, sample_dict
is a fixture that returns a dictionary. It’s used as an argument in the test function to inject the sample dictionary into the test.
Parameterized Testing:
You can also parameterize test functions, running them multiple times with different arguments.
import pytest
@pytest.mark.parametrize("a,b,expected", [(1, 2, 3), (4, 5, 9), (10, 20, 30)])
def test_addition(a, b, expected):
assert a + b == expected
Plugins and Configurations:
pytest
allows you to use plugins and configure your testing regime.- Common plugins include
pytest-django
for Django applications,pytest-asyncio
for testing asyncio code,pytest-cov
for coverage reporting, and many more. - Customize
pytest
usingpytest.ini
orpyproject.toml
to add configuration settings and default markers.
Skipping and Expected Failure:
- Use
@pytest.mark.skip
or@pytest.mark.skipif
to skip certain tests. @pytest.mark.xfail
can mark tests as expected to fail.
Test Discovery:
- By default,
pytest
identifies all files that match the patterntest_*.py
or*_test.py
as test files. - Within test files, any function prefixed with
test_
is considered a test.
Example Test File:
import pytest
# A sample fixture
@pytest.fixture
def sample_value():
return 42
# A basic test
def test_sample_value(sample_value):
assert sample_value == 42
# Parameterized test
@pytest.mark.parametrize("a,b,expected", [(1, 1, 2), (2, 3, 5)])
def test_addition(a, b, expected):
assert a + b == expected
# Skipping a test
@pytest.mark.skip(reason="Skip this test.")
def test_skip_example():
assert 3 == 4
# Expected failure
@pytest.mark.xfail
def test_xfail_example():
assert 4 == 5
.
Certainly! Below are examples of some Python code along with respective pytest
tests.
Example 1: Simple Function Test
Function to Test
# my_sum.py
def my_sum(a, b):
return a + b
Test
# test_my_sum.py
from my_sum import my_sum
def test_my_sum():
assert my_sum(2, 3) == 5
assert my_sum(1, 1) == 2
Run Test:
pytest test_my_sum.py
Example 2: Testing a Class
Class to Test
# person.py
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def get_older(self, years):
self.age += years
Test
# test_person.py
from person import Person
def test_person_get_older():
p = Person("Alex", 30)
p.get_older(5)
assert p.age == 35
Run Test:
pytest test_person.py
Example 3: Fixture Use
Function to Test
# my_multiply.py
def my_multiply(a, b):
return a * b
Test
# test_my_multiply.py
import pytest
from my_multiply import my_multiply
@pytest.fixture
def sample_values():
return 10, 5
def test_my_multiply(sample_values):
a, b = sample_values
assert my_multiply(a, b) == 50
Run Test:
pytest test_my_multiply.py
Example 4: Parameterized Test
Function to Test
# my_divide.py
def my_divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero!")
return a / b
Test
# test_my_divide.py
import pytest
from my_divide import my_divide
@pytest.mark.parametrize("a,b,result", [(10, 2, 5), (20, 4, 5), (30, 3, 10)])
def test_my_divide(a, b, result):
assert my_divide(a, b) == result
def test_divide_by_zero():
with pytest.raises(ValueError, match="Cannot divide by zero!"):
my_divide(10, 0)
Run Test:
pytest test_my_divide.py
These are basic examples of how to structure and create tests using pytest
. It’s an illustrative guide and in real projects, the functions and class methods might be more complex and might require more sophisticated testing mechanisms.
Conclusion:
pytest
offers a robust and comprehensive testing solution for Python developers. Its simplicity, extensibility, detailed failure reports, and a plethora of plugins make it an excellent choice for projects of all sizes. Make sure to explore the pytest
documentation to dive deeper into its powerful features