Pytest Running with Another Version of Python

pytest running with another version of python

Bottom line: run

  • python -m pytest, or
  • py.test-<version> if your alternative Python and pytest are installed with system package manager, or
  • if your alternative Python has been installed with pyenv, switch with pyenv to that version and make sure you have pytest installed for it. Then you can just run pytest.

    • since the pip executable is also among the ones being switched, you need to switch to the alternative Python before installing pytest for it, too.

As I can see, /usr/bin/pytest (that belongs to the system package manager's python-pytest package) has a shebang !#/usr/bin/python since it corresponds to the system python's installation.

pyenv, as its README.md says, does not replace /usr/bin/python - because it indeed should not be replaced to avoid breaking system packages.

Instead, it adds its directory to PATH and inserts a launcher there (called "shim") which is what gets invoked when you type "python". As you probably guessed, this hack is ignored by a shebang like the above - as it should.

  • Running python -m pytest will make whichever python that launches itself use the package from its installation.
  • Alternatively, pytest for your other Python version may include versioned executables on the PATH named py.test-<version> (e.g. py.test-3 or py.test-3.6) depending on the way you installed it.

    • If it's from a system package manager's package for nonstandard python - like python36-pytest - this is virtually guaranteed.
    • I checked that if you install a version with pip, it only creates an unversioned executable (though you can create a versioned one yourself). Moreover, if you install the same package for a different Python version but with the same --prefix, it will overwrite the existing one's executable!
  • pyenv's suggested way seems to be to install all python versions of interest and packages for them under ~/.pyenv/versions.

    • This is not applicable for the system's Python but the default /usr/local can be used for it.
    • Once you switch to an alternative Python version, it claims to create shims for all scripts (including pip!) that are currently installed for that version, so invoking those scripts without a path would run those shims.

      • So, if a package (and thus its script) is not installed for the alternative version but installed for system version, trying to run its executable would "fall through" to /usr/local with just the result you're seeing now.

Pytest how to specify python version per test function

pytest allows you to conditionally skip tests by using the skipif decorator.

@pytest.mark.skipif(sys.version_info >= (3, 9))
def test_base_callback_call():
...

https://docs.pytest.org/en/6.2.x/skipping.html#id1

Pytest and Python 3

I found a workaround:

  1. Installed python3-pip using aptitude, which created /usr/bin/pip-3.2.
  2. Next pip-3.2 install pytest which re-installed pytest, but under a python3.2 path.
  3. Then I was able to use python3 -m pytest somedir/sometest.py.

Not as convenient as running py.test directly, but workable.

Run every pytest test function simultaneously with another function

Fixtures are a perfect use case for this.

See the following hypothetical example --

import pytest

@pytest.fixture
def record_video():
record.start()
yield
record.stop()

@pytest.fixture(scope="session")
def generate_report():
yield
report.make()

Running one test with different versions of fixture

I think parametrized fixture is what will work for you very well:

import pytest

@pytest.fixture
def backends():
"""Mapping of possible backend ids to their constructor functions."""
return {
1: connect_to_backend_1,
2: connect_to_backend_2
}

@pytest.fixture(scope="session", params=[1, 2])
def backend(request, backends):
"""Parametrized backend instance."""
return backends[request.param]()

def test_contract_method_1(backend):
result = run_contract_method_1()
assert result == backend.get_data()

def test_contract_method_2(backend):
result = run_contract_method_2()
assert result == backend.get_data()

This is not live yet, but at least you'll get better understanding if you read this fully:

https://bitbucket.org/pytest-dev/pytest/src/da9d03b1f91d63ec97a989804bacfc03204b0e12/doc/en/fixture.txt?at=default



Related Topics



Leave a reply



Submit