5

I am building a package that provides (1) a fixed interface with (2) pluggable drivers. The desired driver will be selectable by the user of the package. My package will include at least one driver with it, but I would like other developers to be able to implement and validate drivers that conform to the package's interface. As such, I would like these developers to be able to run my tests against their drivers.

Currently, I am using py.test's parametrized fixtures to inject my driver(s) into my tests:

# conftest.py
import my_pkg
import pytest

@pytest.fixture(params=[my_pkg.MyDriver])
def driver(request):
    return request.param
# my_pkg/tests/conftest.py
import my_pkg
import pytest

@pytest.fixture
def my_interface(driver):
    return my_pkg.MyInterface(driver)
# my_pkg/tests/test_my_interface.py
def test_that_it_does_the_right_thing(my_interface):
    assert my_interface.some_method() == "some return value"

I structured it this way in the hopes that someone would be able to collect and run my tests against their version of the driver fixture. In other words, their package would look something like this:

# setup.py
from setuptools import setup

setup(
    # ...
    install_requires=["my-pkg"])
# conftest.py
import their_pkg
import pytest

@pytest.fixture(params=[their_pkg.TheirDriver])
def driver(request):
    return request.param

Obviously this is not enough to get it to work, because py.test doesn't appear to offer an option to inject tests from external packages. But how, if at all, is this possible?

(This question seems to be conceptually similar, but the author appears to be working entirely within one codebase. I would like a completely separate pip-installed package to be able to reference tests included in my pip-installed package.)

1 Answer 1

4

I solved this by:

  1. implementing a custom py.test collector that grafts the necessary suite of tests from my package,
  2. requiring the consumer to instantiate a custom class of mine, my_pkg.MyDriverSuite, in one of their test files, then,
  3. writing a custom py.test plugin that uses the pytest_pycollect_makeitem hook to intercept the custom instance and inject my collector.

(Note: This approach obviated the use of parametrized fixtures.)


The custom collector was by far the trickiest part to figure out, as it required lots of digging through the py.test internals and, ultimately, re-implementing a stripped-down version of a core py.test collector, Session, with a custom session Config whose rootdir was set to that of my package.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi @ian-lesperance, looking back at this after a few years, are you still happy with your solution and are you aware of any other solutions that perhaps require less changes?
An alternative solution may be described here: github.com/pytest-dev/pytest/issues/421#issuecomment-943386533

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.