pythontestingpytesttoxpytest-dependency

pytest not acknowledging PASSED dependency in base class results in SKIPPED tests in derived class


I have this little project where I use pytest and pytest-dependency with tox to develop integration tests on some code. Until now I used one base class (BTestClass) with some common tests in the root directory and the specific tests for each code component in a test_Component.py file next to it implementing a TestC class that inherits from BTestClass.

Everything worked fine until then. Now I want to add a BTestClass2 for another set of components. So I added another layer of inheritance, but now it doesn't work, pytest validates the common A tests but then skips the tests that depend on it. I have no idea why.

Here's the filesystem layout:

λ tree /F
Folder PATH listing
Volume serial number is F029-7357
C:.
│   B.py
│   requirements-tox.txt
│   tox.ini
│
├───app_C
│   └───tests
│           test_C.py
│
└───common
        A.py

common\A.py

import pytest


class ATestClass():

    @pytest.mark.dependency(name='test_a')
    def test_a(self):
        assert True

B.py

import pytest
from common.A import ATestClass


class BTestClass(ATestClass):

    @pytest.mark.dependency(name='test_b', depends=['test_a'])
    def test_b(self):
        assert True

test_C.py

import pytest
import sys


sys.path.append('.')
from B import *


class TestC(BTestClass):

    @pytest.mark.dependency(name='test_c', depends=['test_b'])
    def test_c(self):
        assert True

pytest output:

λ tox -- -rs
py38 installed: ...
py38 run-test-pre: PYTHONHASHSEED='367'
py38 run-test: commands[0] | pytest -x -v -rs
=============================================== test session starts ===============================================
platform win32 -- Python 3.8.1, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 -- ...\poc\.tox\py38\scripts\python.exe
cachedir: .tox\py38\.pytest_cache
rootdir: ...\poc
plugins: dependency-0.5.1
collected 3 items

app_C/tests/test_C.py::TestC::test_b SKIPPED                                                                 [ 33%]
app_C/tests/test_C.py::TestC::test_c SKIPPED                                                                 [ 66%]
app_C/tests/test_C.py::TestC::test_a PASSED                                                                  [100%]
============================================= short test summary info =============================================
SKIPPED [1] .tox\py38\lib\site-packages\pytest_dependency.py:103: test_b depends on test_a
SKIPPED [1] .tox\py38\lib\site-packages\pytest_dependency.py:103: test_c depends on test_b
===================================== 1 passed, 2 skipped, 1 warning in 0.14s =====================================
_____________________________________________________ summary _____________________________________________________
  py38: commands succeeded
  congratulations :)

Any idea why test_b is skipped and not executed?

Edit: If I make BTestClass standalone, removing A / ATestClass from the picture, it works fine.

collected 2 items

app_C/tests/test_C.py::TestC::test_b PASSED [ 50%]
app_C/tests/test_C.py::TestC::test_c PASSED [100%]

Solution

  • In pytest-dependency, a dependency on another test implies that that test runs before the dependent test. If that is not the case (in your example test_b is run before test_a, because test_a is located in a subdirectory), the test is just skipped. pytest-dependency doesn't do any reordering of tests (unfortunately).

    If you cannot easily establish the order in which tests are run via naming, you may use the pytest-ordering plugin to bring the tests into the needed order. In your case you could do:

    class ATestClass:
        @pytest.mark.dependency(name='test_a')
        @pytest.mark.run(order=0)
        def test_a(self):
            assert True
    ...
    class BTestClass(ATestClass):
        @pytest.mark.dependency(name='test_b', depends=['test_a'])
        @pytest.mark.run(order=1)
        def test_b(self):
            assert True
    

    In this case, the tests are run in the order test_a - test_b - test_c, and all tests will run.

    UPDATE:
    You can also use pytest-order, which is a fork of pytest-ordering. If you use the pytest option --order-dependencies it will try to re-order the tests with dependencies created by pytest-dependencies, without the need to add extra marks.

    Disclaimer: I'm the author of that fork.