Using pytest where test in subfolder

Well I kind of solved it, not sure it is the best way but it is working:

In each of the tests:

  1. I check if the test is being executed from it directory or from \Main\Tests
  2. If it is being executed from \Main\Tests then I chdir to \Main\Tests\A_test

I do this under the def setUpClass method.

For example:

@classmethod
def setUpClass(cls):
    if (os.path.exists(os.path.join(os.curdir, "A_test"))):
        os.chdir("A_test")

This makes the test pass no matter if it is executed from Tests folder (with pytest) or from A_test folder (through pycharm)


Option A — Minimal solution

At the root of your project, create a file called tests.py with the following in it

import os, pathlib
import pytest

os.chdir( pathlib.Path.cwd() / 'Tests' )

pytest.main()

You can then use the command python tests.py to run the tests.




Option B — With batch/bash test runners

For those who prefer using batch/bash to run scripts, we can change directories within batch/bash, and then call a Python script that runs the pytest framework. To do this, create the following scripts in the project folder.

test.bat (for Windows)

@echo off

cd /d %~dp0Tests
python %~dp0Tests/runner.py %*
cd /d %~dp0

test.sh (for Linux)

cd $PWD/Tests
python runner.py $@
cd $PWD

And then in the Tests folder, create a file called runner.py with the following

import pathlib, sys
import pytest

cwd = pathlib.Path.cwd()

# Add the project's root directory to the system path
sys.path.append(str( cwd.parent ))

# This is optional, but you can add a lib directory 
# To the system path for tests to be able to use
sys.path.append(str( cwd / 'lib' ))

pytest.main()

If your directory structure includes some type of lib folder within your Tests folder, we can instruct pytest to ignore it by creating a pytest.ini config file with the following.

[pytest]
norecursedirs = lib

Under this scenario, your directory/file structure would end up being:

root
├── test.bat
├── test.sh
├── Main
└── Tests
    ├── runner.py
    ├── pytest.ini # Optional pytest config file
    ├── lib # Optional, contains helper modules for the tests
    ├── tests # Tests go here
    └── # Or, in the OPs case, you could also place all of your tests here




Additional Comments

The methods above aren't the typical way of running pytest, but I prefer using pytest.main() because it allows us to:

  • Have any directory structure.
  • Execute code before the test runner starts.
  • And you can still pass in command line options, and it will behave exactly the same as if you were running the pytest command directly.

Adding __init__.py to the package of the tests worked for me. All test are executed afterwards.