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

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)

Related

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 iterate a Pytest test with fixture which does setup and teardown

I am very new to pytest.
There is a test_conf dir which has several test config files.
test_conf
test_conf1
test_conf2
Here is my test function.
conf_files function gets all test_conf files from that dir and returns a list.
#pytest.mark.parametrize('test_conf', conf_files())
def test_performance_scenario_1(fixture1, test_conf):
do_some_thing(test_conf)
The fixture1 does setup and teardown for this test.
My proposal is for each test conf file from test_conf, we run test function to do some test against it.
My question is how to pass each element of test_conf to fixture1, since I need to do some initialization in fixture1 setup step which needs the test conf file.
Any help is appreciated.
I think what you're looking for is parameterised fixtures. So instead of passing the conf files to your test, you pass it to the fixture, which does the setup/teardown with the particular conf file.
definition of your fixture1:
#pytest.fixture(scope="module", params=conf_files())
def fixture1(request):
# The pytest fixture `request` gives you access to the params defined in the annotation.
conf_file = request.param
# setup / teardown logic
...
Then in your test, it suffices to only pass the fixture:
def test_performance_scenario_1(fixture1):
# do_some_things

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

How to disable pytest fixtures?

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)?

How to run specific code after all tests are executed?

I would like to run specific code after all the tests are executed using pytest
for eg: I open up a database connection before any tests are executed. And I would like to close the connection after all the tests are executed.
How can i achieve this with py.test? Is there a fixture or some thing that can do this?
You can use a autouse fixture with session scope:
#pytest.fixture(scope='session', autouse=True)
def db_conn():
# Will be executed before the first test
conn = db.connect()
yield conn
# Will be executed after the last test
conn.disconnect()
You can then also use db_conn as an argument to a test function:
def test_foo(db_conn):
results = db_conn.execute(...)