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

Programatically generate test parameters (parameters generators?)

Open ant1j opened this issue 1 year ago • 1 comments

Bonjour,

I just discover this plugin and it looks like it might help me to achieve what I am looking for in terms of tests. If I try to get a minimal working example of what I need is:

  • One of the test could be: for a given column (list of numbers), test that the sum of the all cells but the last equals the last (sum of the parts equals total)
  • I have multiple columns to test (e.g. in a dataframe)
  • I have multiple dataframes in one file (e.g. Excel files with multiple tabs)
  • I have multiple files

The test is always the same for all the columns that are identified, so I guess the test is unique but the parameters are the product of all the components (files x dataframes x columns) But I cannot find the proper way to "make it happen"...

In the documentation, the part Case Generator looks promising but the list of all values is hard-coded (@parametrize(who=('you', 'there'))).

I was wondering if there is a way to programmatically generated the values of the fixtures or cases.

What I would imagine:

@fixture
@parametrize(file=list_of_files_from_glob, key=list_of_keys)
def df_from_file(file, key)
    return pd.read_excel(file, sheet_name=key)

@fixture
@parametrize(df=df_from_file()) # <-- This is not possible but this is what I am trying to achieve...
def column(df):
    filter = get_filter_info(df)
    for col in filter_cols(df):
        yield df[col] # <-- Generator are not possible but this is the idea

@parametrize(col=column())  # <-- same...
def test_sum_of_parts(col)
    # here col are all the cols from all the dfs from all the tabs/keys from all the files...
    assert np.isclose(col[;-1].sum(), col[-1])

I will keep on reading the documentation to find some hints. The fixtures unions looks like an option but I am lost so far in the way it works. Thanks in advance for your help.

ant1j avatar Sep 03 '24 16:09 ant1j

You might have fell in the classic fixture-parameter trap from pytest : https://github.com/smarie/python-pytest-cases/issues/235 this is why I pinned that issue at the top of the repo ;)

In pytest, it is not possible to dynamically create parameters INSIDE a fixture. So you have to load your files and extract the list of (files+tabs) directly in code that is just after your module imports.

Once this list is obtained, you can use it in the @parametrize decorators:

imports....

# Here, read all files, extract the tabs
tabs = ...

# Now you can use them to parametrize something (a fixture, or a test). For example
@fixture
@parametrize("tab", tabs)
def df(tab)
    ....
    return _df

def test_xxx(df)
    # use the dataframe

smarie avatar Sep 09 '24 13:09 smarie