Set up pytest with a separate test directory

Wow, Python can be painful sometimes.

I was setting up a test directory for my project. The repo structure is

├── pyproject.toml
├── requirements.txt
├── src
│   ├── __init__.py
│   ├── presentation.py
│   └── weatherdl.py
├── tests
│   ├── __init__.py
│   └── a_test.py

I tried a few different ways of importing my project source code into the test directory. One way that appeared promising was importing via a context file. Another way was to create a __init__.py file in the tests directory with code to modify the system path:

import os
import sys
PROJECT_PATH = os.getcwd()
sys.path.append(PROJECT_PATH)

Problem

Both of these methods appeared to work initially, but they had the weird problem that I could only import one of my source files.

The following code worked fine:

import presentation

def a_test():
    assert True == True

but as soon as I added another import, the code failed!

import presentation
import weatherdl

def a_test():
    assert True == True
ModuleNotFoundError: No module named 'presentation'

Solution

The pytest documentation explains that the default import mode is prepend not importlib. I don’t fully understand the difference, but the text contains this little gem.

The importlib import mode does not have any of the drawbacks above, because sys.path is not changed when importing test modules.

My experience of having imports work when there is one of them, and not otherwise, is probably due to the sys.path being changed by the imports themselves.

The solution was to change pytest to use importlib mode. To do this, I created a pyproject.toml file in the repository root with the following contents.

[tool.pytest.ini_options]
addopts = [
    "--import-mode=importlib",
]
pythonpath = "src"

And that’s it!

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *