Writing tests
Use pytest
I initially based my tests on this excellent article, particularly part 2. However I found that two of its key recommendations, inheriting from unittest.TestCase
and use of the parameterized
package, seemed to make things harder when I came to do more complicated tests. For example it was difficult to find any help on how to use unittest.mock.patch
(or my current choice, pytest-mock
, which wraps this into mocker
) with parameterized. Sticking within the pytest package has made things easier in this regard.
Therefore, my current approach to unit tests is to write bare functions (no classes) with plain assert
statements. If I need to parameterize a function I use pytest.parametrize
and if I need to patch something I use mocker
from pytest-mock. For other mocking I use the classic unittest.MagicMock
.
Where possible I try to write code that avoids the need for patching during tests. I use dependency injection or callbacks such that if function A needs to call function B, function B is passed to function A as an argument. For example, the code below makes is easy to have multiple data_getters
perhaps one for disk one for database, one for remote API etc. but it also makes it very easy to pass a mock getter for unit testing. Of course I don't do this absolutely everywhere, just in places where is helps.
1 2 3 4 5 6 7 8 9 10 |
|
Test dependencies
To let me quickly run my tests while developing I like to install my test dependencies into my dev environment using poetry add --dev
.
This adds them to pyproject.toml
as shown.
ini linenums=1
[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
pytest-cov = "^2.12.1"
pytest-mock = "^3.6.1"