In this Answer, we'll learn how to write a unit test for a Django application. We'll also learn where to start and how to use pytest as a testing tool.
Before starting, let's discuss what pytest is and how important it is in our tech journey.
In Python, pytest is a testing framework for writing and executing tests. It is an easy way to design and run tests for our software projects of any size or capacity.
Let's talk about fixtures and how they work in pytest.
Fixtures are functions that let us define reusable test setups. To simplify, fixtures are test functions that let us define specific data such as database connections, URLs used for testing, or user input data.
Fixtures help us initialize our data before running our tests and in cleaning upon restoring the state of the data after the test has been executed.
Fixtures are defined with a special decorator, @pytest.fixture
. A test function uses fixtures by calling the name of the fixture as an input parameter.
Note: Before we define a fixture, we need to import
pytest
at the top of our Python file.
import pytest@pytest.fixturedef non_string_data():return 30def test_non_string_data_1(non_string_data):assert isinstance(non_string_data, int)assert non_string_data > 0def test_non_string_data_2(non_string_data):assert isinstance(non_string_data, int)assert non_string_data % 2 == 0def test_string_data(non_string_data):with pytest.raises(TypeError):assert isinstance(non_string_data, str)
In the code snippet above, we have a fixture function name non_string_data
that gives data to the tests. The fixture is accessed by specifying it as an argument or as an input parameter.
Under the hood, when the test is run, Pytest
recognizes the fixture
name as an input and runs the fixture
function, returning the result saved in the input argument used by the test.
To run our pytest, we can choose to either run pytest
on our terminal or use expressions to get a more specific output. Either way, our test would either fail or pass.
Let's run our pytest using expressions.
On the terminal, we'll run python -m pytest -k data -v
.
The output would look like this:
================================================= test session starts =================================================...collected 3 itemstest_sample.py::test_non_string_data_1 PASSED [ 33%]test_sample.py::test_non_string_data_2 PASSED [ 66%]test_sample.py::test_string_data FAILED [100%]====================================================== FAILURES =======================================================_______________________________________________ test_string_data ________________________________________________non_string_data = 42def test_string_data(non_string_data):> with pytest.raises(TypeError):E Failed: DID NOT RAISE <class 'TypeError'>test_sample.py:16: Failed================================================ 2 passed, 1 failed in 0.07 seconds ================================================
Let's dissect the expressions.
-k
is used to select specific tests based on the given substring and in this code snippet, it's data
. It means only test functions with data in their names would be executed.
-v
enables the verbose input by giving more information about the test executed.
Fixtures have their restrictions. Fixture functions defined in a test file can only be used within that test file; they cannot be exported to another. However, if we want to export or import the fixture, we must first create a confest.py
file and define all fixture functions in it.
The confest.py
file is recognized by pytest and allows us to define and exchange fixtures, plug-ins, and so on across test files in our project. It acts as a configuration file for the project or directory.