python-pytest-cases
python-pytest-cases copied to clipboard
Question: Is it possible to have a set of default test cases being overridden?
Hi,
I am looking into your interesting plugin and like the separation of concerns cases and tests. My question is, if there is already a mechanism to override default cases based on attribute like a fixture for example:
a_condition = True
class cases_featureA_default:
def case_int_1_success(self, env):
return env
def case_int_2_success(self):
return 1
class cases_featureA_specific:
def case_int_1_success(self):
return 1
@fixture
def select_cases():
if a_condition:
return cases_featureA_specific
return cases_featureA_default
class TestFeatureA:
@parametrize_with_cases(
"data",
prefix="case_",
glob="*success",
cases=select_cases,
)
def test_A_1(self, data):
assert sqrt(data) > 0
Or is this generally solved with a different logic?
Regards Mischa
Hi @MischaZihler , thanks for the interesting question !
If I understand correctly, your question relates to the general scenario of reusing a collection of cases (e.g. class CasesA across various tests (e.g. test_a and test_b), and you are interested in the possibility of keeping some flexibility, for example having one of the cases in CasesA overridden when the collection is used in test_b.
Such static flexibility could I guess, be done with subclasses (CasesAOverridden would inherit from CasesA and override only some of the cases) but currently this is not working:
from pytest_cases import parametrize_with_cases
class ACases(object):
@staticmethod
def case_static_overridden():
return 1
@staticmethod
def case_static_inherited():
return 2
def case_normal_overridden(self):
return 1
def case_normal_inherited(self):
return 2
class ACasesOverridden(ACases):
@staticmethod
def case_static_overridden():
return 3
def case_normal_overridden(self):
return 3
@parametrize_with_cases("nb", cases=ACases)
def test_less_than_2(nb):
assert nb <= 2
@parametrize_with_cases("nb", cases=ACasesOverridden)
def test_more_than_2(nb):
assert nb >= 2
This leads to an error:
File "C:\_dev\python_ws\_Libs_OpenSource\python-pytest-cases\src\pytest_cases\case_parametrizer_new.py", line 914, in _extract_cases_from_module_or_class
m_def_in_cls = cls.__dict__[m_name]
KeyError: 'case_normal_inherited'
So today, inheritance of cases between cases classes is currently not supported. I should make that more explicit in the error message.
A simple workaround for now is to list all cases that are inherited, explicitly:
class ACasesOverridden(ACases):
@staticmethod
def case_static_overridden():
return 3
def case_normal_overridden(self):
return 3
# For staticmethod and classmethod, you need to ref the __dict__
case_static_inherited = ACases.__dict__['case_static_inherited']
# For standard methods this is more straightforward
case_normal_inherited = ACases.case_normal_inherited
So for all inherited methods, either you redefine them or you explicitly list them. This seems to work fine from what I've tested.
Would this be what you're looking for or are you chasing a more complex use case ? Note that dynamically switching between parameters (for example based on a fixture's code content) is not possible in pytest, because pytest works with a static plan: (1) it collects all parameters and fixture definitions without executing anything, and (2) it executes the plan