How to disable pytest fixtures? - pytest

I'm trying to run fixture tests separately from the classic unit tests.
For that end, I've marked all the fixtures with #pytest.mark.fixtures decorator, for example:
conftest.py
#pytest.fixture(scope="session")
def fs():
pass
test_something.py
#pytest.mark.fixtures
def test_xxx(fs):
pass
#pytest.mark.fixtures
def test_yyy():
pass
and then ran two pytest commands (within tox):
pytest -v -m fixtures --junitxml={toxinidir}/tests/output/pytest-fixtures.xml
pytest -v -m "not fixtures" --junitxml={toxinidir}/tests/output/pytest.xml
The problem is that the second pytest run still creates my session fixture, although I will not use it because I'm skipping the tests marked with the above fixtures mark.
How can I disable the fixture on the second "not fixtures" run (or skip the session-scoped fixture)?

Related

Pytest skipping a test class that inherits from a builtin

TLTR:
The question is maximally easy: Please look at the code base case. Pytest just ignoring this class. How I should run tests on a such class?
I just started switching from a simple python tests (with just assert) to testing with pytest and come across with this problem. Most of my tests is are classes that extending a real classes with test methods. One of my classes inherit from collections.UserDict. Pytest just ignoring this class. How I should run tests on a such class?
# Inheritance from object are ok, Inheritance from dict are not ok. Need dict :(
class TestFoo(dict):
def test_foo(self):
assert 1
output:
/home/david/PycharmProjects/proj/venv/bin/python /snap/pycharm-professional/302/plugins/python/helpers/pydev/pydevd.py --multiprocess --qt-support=auto --client 127.0.0.1 --port 44145 --file /snap/pycharm-professional/302/plugins/python/helpers/pycharm/_jb_pytest_runner.py --path /home/david/PycharmProjects/proj/tests/unit_tests_2.py
Testing started at 11:07 ...
Launching pytest with arguments /home/david/PycharmProjects/proj/tests/unit_tests_2.py --no-header --no-summary -q in /home/david/PycharmProjects/proj/tests
============================= test session starts ==============================
collecting ... collected 0 items
============================= 2 warnings in 0.03s ==============================
Process finished with exit code 5
Empty suite
UPD Thanks for #Teejay Bruno, running tests from pycharm hiding a warning from me:
PytestCollectionWarning: cannot collect test class 'TestFoo' because it has a __init__ constructor
The warning tells you the problem:
PytestCollectionWarning: cannot collect test class 'TestFoo' because it has a __init__ constructor
If I understand what you're trying to do, why not just pass the object as a fixture?
import pytest
#pytest.fixture
def my_dict():
return dict()
class TestFoo:
def test_foo(self, my_dict):
assert len(my_dict) == 0

How to use pytest reuse-db correctly

I have broken my head trying to figure out how --reuse-db. I have a super-simple Django project with one model Student and the following test
import pytest
from main.models import Student
#pytest.mark.django_db
def test_1():
Student.objects.create(name=1)
assert Student.objects.all().count() == 1
When I run it for the first time with command pytest --reuse-db, the test passes - and I am not surprised.
But when I run the pytest --reuse-db for the second time, I expect that the db is not destroyed and the test fails, because I expect that Student.objects.all().count() == 2.
I am misunderstanding the --reuse-db flag ?
--reuse-db means to reuse the database between N tests within the same test run.
This flag has no bearing on running pytest twice.

How to force Pytest to execute the only function in parametrize?

I have 2 tests. I want to run the only one:
pipenv run pytest -s tmp_test.py::test_my_var
But pytest executes both functions in #pytest.mark.parametrize (in both tests)
How can I force Pytest to execute the only get_my_var() function if I run the only test_my_var?
If I run the whole file:
pipenv run pytest -s tmp_test.py
I want Pytest to execute the code in the following manner:
get_my_var()
test_my_var()
get_my_var_1()
test_my_var_1()
Actually, my functions in #pytest.mark.parametrize make some data preparation and both tests use the same entities. So each function in #pytest.mark.parametrize changes the state of the same test data.
That's why I strongly need the sequential order of running parametrization functions just before corresponding test.
def get_my_var():
with open('my var', 'w') as f:
f.write('my var')
return 'my var'
def get_my_var_1():
with open('my var_1', 'w') as f:
f.write('my var_1')
return 'my var_1'
#pytest.mark.parametrize('my_var', get_my_var())
def test_my_var(my_var):
pass
#pytest.mark.parametrize('my_var_1', get_my_var_1())
def test_my_var_1(my_var_1):
pass
Or how can I achive the same goal with any other options?
For example, with fixtures. I could use fixtures for data preparation but I need to use the same fixture in different tests because the preparation is the same. So I cannot use scope='session'.
At the same time scope='function' results in fixture runs for every instance of parameterized test.
Is there a way to run fixture (or any other function) the only one time for parameterized test before runs of all parameterized instances?
It looks like that only something like that can resolved the issue.
import pytest
current_test = None
#pytest.fixture()
def one_time_per_test_init(request):
test_name = request.node.originalname
global current_test
if current_test != test_name:
current_test = test_name
init, kwargs = request.param
init(**kwargs)

pytest: detect -m "not my_mark" in fixture

It is possible to detect if a mark has been excluded?
I use pytest to run some tests against an embedded target. For some of the test setups, I can control the supply power via an epdu.
For the setups with an epdu, I want to power down the test equipment when the test is finished.
For the setups without epdu the test is called with -m "not power", but here it is also crucial that the power_on fixture will not try to communicate with the epdu
#pytest.fixture(scope='session', autouse=True)
def power_on():
# TODO: just return it called with `-m "not power"`
power_on_test_equipment()
yield
power_off_test_equipment()
#pytest.mark.power_control
def test_something():
power_something_off()
What I found is request.keywords['power'] will be true if I run pytest with -m power but will not exists if I run without the mark or with -m "not power", which is not really helpful for my scenario.
I can solve the problem using two markes, like `-m "no_power and not power", but it does not seem very elegant.
One possibility is just to check for the command line argument. If you know that you are always passing it as -m "not power", you could do something like this:
#pytest.fixture(scope='session', autouse=True)
def power_on(request):
power = 'not power' not in request.config.getoption('-m')
if power:
power_on_test_equipment()
yield
if power:
power_off_test_equipment()

Overriding collection paths via PyTest plugin

With PyTest, you can limit the scope of test collection by passing directories/files/nodeids as command line arguments, e.g., pytest tests, pytest tests/my_tests.py and pytest tests/my_tests.py::test_1. Is it possible to override this behavior from within a plugin, i.e., to set them to something else programmatically?
So far I've attempted setting file_or_dir to my own list within config.option and config.known_args_namespace from the pytest_configure hook, but this appears to have no effect on anything.
You are probably looking for config.args:
# conftest.py
def pytest_configure(config):
config.args = ['foo', 'bar/baz.py::test_spam']
Running pytest now will be essentially the same as running pytest foo bar/baz.py::test_spam. However, putting stuff in pytest.ini would be IMO a better solution:
# pytest.ini
[pytest]
addopts = foo bar/baz.py::test_spam