Home > Blockchain >  Late-Binding conflict with Pytest module
Late-Binding conflict with Pytest module

Time:11-06

I am trying to iterate pytest over functions, the problem of late-binding makes pytest only apply the test to the last function.
For a simplified example I authored the following test.py file:

import pytest


def func_1(x):
    return (x 10)


def func_2(y):
    return (y-10)


func_1_test_cases = {'func_1': (10, 20)}
func_2_test_cases = {'func_2': (10, 0)}

# Iterating over the functions 
for func in ['func_1', 'func_2']:
    @pytest.mark.parametrize('param, expected',
                             globals()[func   '_test_cases'].values(),
                             ids=list(globals()[func  
                                                '_test_cases'].keys()))
    def test(param, expected):
        eval(func '(param) == expected')

I read more about the late-binding problem and applied suggestions like:

    def test(param, expected, func=func):
        eval(func '(param) == expected')

when using the command: pytest test.py -v
pytest reports collecting only the last function in list(func_2):

plugins: timeout-1.4.2, anyio-2.2.0, pudb-0.7.0 collected 1 item

1.py::test[func_2] PASSED [100%]

============================================================================= 1 passed in 0.01s =============================================================================

func_1 has never been collected
It seems the late-binding problem is tricker when using pytest. I expect pytest report to collect two functions and return their status. I really need a hack around this.

CodePudding user response:

This doesn't directly answer your question about defining multiple tests with the same name, but for the specific example you posted, it would be much easier to include the function itself as one of the test parameters:

import pytest

def func_1(x):
    return (x 10)

def func_2(y):
    return (y-10)

@pytest.mark.parametrize(
        'func,param,expected', [
            pytest.param(func_1, 10, 20, id='func_1'),
            pytest.param(func_2, 10, 0, id='func_2'),
        ],
)
def test(func, param, expected):
    assert func(param) == expected

Just a heads up: your test function doesn't have an assert, so it will pass regardless of whether eval(func '(param) == expected') is true or false.

CodePudding user response:

Inspired by Kale's answer, I believe there is no good way to loop over pytest parametize decorator (hope someone correct me if I am wrong).
The only practical solution is to include the function ids in the parameter list.
Here is a modified code near to what I wanted.

import pytest


def func_1(x):
    return (x 10)


def func_2(y):
    return (y-10)

func_test_cases = {'func_1': (10, 20, 'func_1'), 'func_2': (10, 3, 'func_2')}


@pytest.mark.parametrize('param, expected, func',
                         func_test_cases.values(),    ids=func_test_cases.keys())
def test(param, expected, func):
    assert eval(func '(param) == expected')
  • Related