Reputation: 537
I'm using tox to run tests in my CircleCI deployment. I have a directory called tests
, and within this directory I have another directory called test_files
with files I use for mocking, e.g., files with JSON data. Locally I run the tests successfully with the mock files, but in CircleCI, pytest cannot find the JSON files within the directory: FileNotFoundError: [Errno 2] No such file or directory: 'test_files/data.json'
This is my tox.ini
:
[tox]
envlist = py37,py38,flake8
[testenv]
deps=-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands=
pytest -v tests
and my config.yml
:
version: 2
jobs:
# using tox
toxify:
docker:
- image: python:3.8
steps:
- checkout
- run:
name: tox build
command: |
pip install tox
tox -q
- run:
name: deploy
command: |
./deploy.sh
workflows:
version: 2
build_and_release:
jobs:
- toxify:
filters:
tags:
only: /^v\d+\.\d+\.\d+$/
Test example:
from my_package.image import ImageValidator
def test_valid_image():
image_validator = ImageValidator("test_files/default_image.png")
assert image_validator.is_valid_image() is True
I open the image with:
file_path = glob.glob(os.path.join(os.path.dirname(file_path), '*.png'))[0]
with open(file_path, "rb") as image:
image_data = image.read()
...
Am I missing something?
Upvotes: 2
Views: 1819
Reputation: 66171
Restating the comments: if you use relative paths in your code:
def test_valid_image():
image_validator = ImageValidator("test_files/default_image.png")
the path test_files/default_image.png
will be resolved relative to the current working directory, so if the full path is e.g.
/root/tests/test_files/default_image.png
the file will be found only if you run the test from /root/tests
: cd /root/tests; pytest
will work, while every other workdir, e.g. cd /root; pytest tests/
will fail. This is what currently happens in your tox
config:
commands=
pytest -v tests
starts pytest
in project root, looking for tests in tests
directory, so test_files/default_image.png
resolves to project root/test_files/default_image.png
and not project root/tests/test_files/default_image.png
as you would expect.
There are many ways to circumvent this. Best is to resolve the paths relative to some static file, e.g. the calling module:
def test_valid_image():
path = os.path.join(__file__, '..', '..', 'test_files', 'default_image.png')
image_validator = ImageValidator(path)
or, by knowing that pytest
stores project root in its configuration:
def test_valid_image(request):
rootdir = request.config.rootdir
path = os.path.join(rootdir, 'tests', 'test_files', 'default_image.png')
image_validator = ImageValidator(path)
Now the path will be resolved ignoring the working directory and tied to a file that has always the same path; running pytest tests/
or cd tests/; pytest
has now the same effect.
Other ways are playing with changing the working directory. Since your test expect to be executed from tests
dir, navigate to it in the tox.ini
:
commands=
cd tests && pytest; cd ..
or
commands=
pushd tests; pytest; popd
etc.
Upvotes: 3