liorblob
liorblob

Reputation: 537

CircleCI - pytest cannot find files used by tests

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

Answers (1)

hoefling
hoefling

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

Related Questions