python-pytest-cases icon indicating copy to clipboard operation
python-pytest-cases copied to clipboard

Feature Request: Ability to define fixtures in case file

Open Jasha10 opened this issue 4 years ago • 4 comments

Currently it seems that fixtures must be defined in test_foo.py, and defining a fixture in test_foo_cases.py does not work. It would be nice if fixtures defined in test_foo_cases.py could be used within the same file.

Motivation

If the test cases defined in test_foo_cases.py will use a fixture, being able to those fixtures in the same file would be good for organization (data locality).

Repro:

Currently the following does not work:

# test_foo.py
from pytest_cases import parametrize_with_cases

@parametrize_with_cases("test_case")
def test_simple(test_case):
    assert test_case == 124
# test_foo_cases.py
from pytest_cases import fixture
@fixture
def fixt():
    return 123

def case_simple(fixt):
    return fixt + 1

This fails as follows:

$ pytest
================================================================== test session starts ==================================================================
platform linux -- Python 3.9.6, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /home/jbss/pysc/tensor_from_dom2
plugins: cov-2.12.1, hydra-core-1.1.1, cases-3.6.3
collected 1 item

test_foo.py E                                                                                                                                     [100%]

======================================================================== ERRORS =========================================================================
_________________________________________________________ ERROR at setup of test_simple[simple] _________________________________________________________
file /home/jbss/pysc/tensor_from_dom2/test_foo.py, line 3: source code not available
file <makefun-gen-8>, line 1: source code not available
file <makefun-gen-6>, line 1: source code not available
E       fixture 'fixt' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, current_cases, doctest_namespace, hydra_restore_singletons, hydra_sweep_runner, hydra_task_runner, monkeypatch, no_cover, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, simple, symbol_id, test_simple_test_case, tick_size, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

<makefun-gen-6>:1
================================================================ short test summary info ================================================================
ERROR test_foo.py::test_simple[simple]
=================================================================== 1 error in 0.02s ====================================================================

Workaround

The fixture can be defined in test_foo.py or in conftest.py:

# test_foo.py
from pytest_cases import fixture, parametrize_with_cases

@fixture
def fixt():
    return 123

@parametrize_with_cases("test_case")
def test_simple(test_case):
    assert test_case == 124
# test_foo_cases.py
def case_simple(fixt):
    return fixt + 1
$ pytest
...
=================================================================== 1 passed in 0.02s ===================================================================

This is documented in the Cases Requiring Fixtures section of the docs: "make sure the fixture exists or is imported either in the module where @parametrize_with_cases is used, or in a conftest.py file in one of the parent packages."

Possibly related to this issue: https://github.com/smarie/python-pytest-cases/issues/174

Jasha10 avatar Aug 26 '21 12:08 Jasha10

Thanks for the feedback @Jasha10 !

I think that the workaround for issue #174 should solve your issue as well, did you try ?

# test_foo.py
from pytest_cases import parametrize_with_cases

from .test_foo_cases import *  # <-- this line does the trick

@parametrize_with_cases("test_case")
def test_simple(test_case):
    assert test_case == 124
# test_foo_cases.py
from pytest_cases import fixture
@fixture
def fixt():
    return 123

def case_simple(fixt):
    return fixt + 1

smarie avatar Aug 27 '21 13:08 smarie

did you try ?

I had not tried this. It works! Thanks for the tip :)

Jasha10 avatar Aug 28 '21 04:08 Jasha10

For those who use the from ... import * trick, make sure your fixture names do not start with an underscore!

According to the python docs, from pytest_cases import * "imports all names except those beginning with an underscore (_)."

Jasha10 avatar Aug 28 '21 20:08 Jasha10

Indeed, thanks for the trick @Jasha10 !

smarie avatar Aug 30 '21 09:08 smarie