Hi Liz,

below and attached is a solution which should fullfill your expectations
and reports this on py.test --collectonly:

    <Module 'test_params.py'>
      <Function 'test_example[std-blue-cat]'>
      <Function 'test_example[std-pink-dog]'>
      <Function 'test_example[pro-blue-cat]'>
      <Function 'test_example[pro-pink-dog]'>
      <Function 'test_something[std]'>
      <Function 'test_old_style[0]'>
      <Function 'test_old_style[1]'>

minor deviation:  The last two old-style ones are parametrized with your
intended parameters, but the reported test id is collapsed.

Lastly, i presume you are aware of @pytest.mark.parametrize, right?
Your @params decorator looks like a version requiring more typing
than neccessary to me :)

HTH,
holger


import pytest

def pytest_generate_tests(metafunc):
    hasmyfixture = "myfixture" in metafunc.fixturenames
    paramlist = getattr(metafunc.function, "paramlist", None)

    if hasmyfixture:
        argvalues = ["std"]
        if paramlist:
            argvalues.append("pro")
        metafunc.parametrize("myfixture", argvalues, indirect=True)

    if paramlist:
        if isinstance(paramlist[0], dict):
            # old-style
            for p in paramlist:
                metafunc.addcall(funcargs=p)
        else:
            assert isinstance(paramlist[0], list)
            argnames = paramlist[0]
            argvalues = [d["argvalues"] for d in paramlist[1:]]
            metafunc.parametrize(argnames, argvalues)

def params(decolist):
    def wrapper(function):
        function.paramlist = decolist
        return function
    return wrapper

class SomeObject:
    def close(self):
        print "closing"

class SomeOtherObject(SomeObject):
    pass

@pytest.fixture
def myfixture(request):
    if request.param == 'std':
        myfix = SomeObject()
    elif request.param == 'pro':
        myfix = SomeOtherObject()
    else:
        assert 0, "unknown param"
    def fin():
        myfix.close()
    request.addfinalizer(fin)
    return myfix

@params([
    ['color', 'type'],
    { 'argvalues': [ 'blue', 'cat'] },
    { 'argvalues': ['pink', 'dog'] }
])
def test_example(myfixture, color, type):
    # this is the new test we want to add
    assert 0

def test_something(myfixture):
    # existing test which only uses std fixture
    assert 0

@params([
    {'arg1': 1, 'arg2': 2},
    {'arg1': 3, 'arg2': 5}
])
def test_old_style(arg1, arg2):
    # existing tests which don't use fixtures
    assert 0


On Fri, Apr 05, 2013 at 17:08 +0000, Elizabeth Lin wrote:
> Hi Holger,
> 
> Thanks for responding! Comments inline below.
> 
> On 4/4/13 11:14 PM, "holger krekel" <[email protected]> wrote:
> 
> >Hi Elizabeth,
> >
> >And sorry for taking a while but i am still not sure i fully understand.
> >I am pretty sure we can find a solution but i'd like to find one that
> >fits the problem :)
> >
> >Could you clarify your problem purely from the test function side?
> >Particularly, if you have this test:
> >
> >    @params([
> >        ['color', 'type'],
> >        { 'argvalues': [ 'blue', 'cat'] },
> >        { 'argvalues': ['pink', 'dog'] }
> >    ])
> >    def test_example(myfixture, color, type):
> >        # this is the new test we want to add
> >        assert 0
> >
> >do i understand it right that ``myfixture`` should be indirectly
> >created by using ["std", "pro"] as respective parameters because
> >there is a @params decorator? And that for
> 
> Yes, myfixture should be indirectly created when we call
> metafunc.parametrize to pass in ["std", "pro"] as parameters, but only for
> specific tests - in this case the tests generated should be:
> - std, blue, cat
> - std, pink, dog
> - pro, blue, cat
> - pro, pink dog
> 
> >
> >    def test_something(myfixture):
> >        # existing test which only uses std fixture
> >        assert 0
> >
> >you only want ``myfixture`` created with the "std" parameter?
> 
> Yes, that's correct.  So only test should be
> - std
> 
> >
> >And that for:
> >
> >    @params([
> >        {'arg1': 1, 'arg2': 2},
> >        {'arg1': 3, 'arg2': 5}
> >    ])
> >    def test_old_style(arg1, arg2):
> >        # existing tests which don't use fixtures
> >        assert 0
> >
> >you don't want any "myfixture" created at all?
> 
> Also correct.  Generated tests should be
> - 1, 2
> - 3, 5
> 
> Cheers,
> Liz
> 
> >
> >
> >cheers,
> >holger
> >
> >
> >
> >On Thu, Apr 04, 2013 at 22:51 +0000, Elizabeth Lin wrote:
> >
> >> Hi, 
> >> 
> >> I have some tests which I'd like to parametrize using both more complex
> >> fixtures as well as simple string arguments.  How are folks doing this
> >> currently?  Or is this a use case that hasn't been seen before?  Using
> >> metafunc.parametrize in a pytest_generate_test hook won't work for me
> >> since I need the fixtures to have indirect=True to pass the argname as a
> >> request.param, but the other arguments to have indirect=False.
> >> 
> >> For example, if I have a test fixture and test case which looks like the
> >> following:
> >> Any suggestions for how to accomplish this would be much appreciated!
> >> 
> >> 
> >> def pytest_generate_tests(metafunc):
> >>    if metafunc.function.__name__ == 'test_example':
> >>            argnames = []
> >>            argvalues = []
> >>            parameters = getattr(metafunc.function, 'paramlist', ())
> >>            for p in parameters:
> >>                    if type(p) == list:
> >>                            argnames = tuple(['myfixture'] + p)
> >>                    else:
> >>                            argvalues.append = tuple(['std'] + 
> >> p['argvalues'])
> >>                            argvalues.append = tuple(['pro'] + 
> >> p['argvalues'])
> >>            # I want to do the following, but it won't work since some of 
> >> the
> >>            # args need indirect set to true
> >>            # and some need indirect set to false.
> >>            metafunc.parametrize(argnames, argvalues, indirect=True)
> >>    elif 'myfixture' in metafunc.fixturenames:
> >>            # we have existing tests which use the fixture, but only with 
> >> std
> >>            metafunc.parametrize("myfixture", "std")
> >>    else:
> >>            # we have existing tests which use older style parametrization,
> >>            # non-fixture
> >>            for p in getattr(metafunc.function, 'paramlist', ()):
> >>                    metafunc.addcall(funcargs=p)
> >> 
> >> 
> >> def params(decolist):
> >>    def wrapper(function):
> >>            function.paramlist = decolist
> >>            return function
> >>    return wrapper
> >> 
> >> @pytest.fixture
> >> def myfixture(request):
> >>    if request.param == 'std':
> >>            myfix = SomeObject()
> >>    elif request.param == 'pro':
> >>            myfix = SomeOtherObject()
> >>    def fin():
> >>            myfix.close()
> >>    request.addfinalizer(fin)
> >>    return myfix
> >> 
> >> @params([
> >>     ['color', 'type'],
> >>     { 'argvalues': [ 'blue', 'cat'] },
> >>     { 'argvalues': ['pink', 'dog'] }
> >> ])
> >> def test_example(myfixture, color, type):
> >>     # this is the new test we want to add
> >> 
> >> def test_something(myfixture):
> >>     # existing test which only uses std fixture
> >> 
> >> @params([
> >>     {'arg1': 1, 'arg2': 2},
> >>     {'arg1': 3, 'arg2': 5}
> >> ])
> >> def test_old_style(arg1, arg2):
> >>     # existing tests which don't use fixtures
> >> 
> >> 
> >> Thanks for reading through this! I know it's rather long.
> >> 
> >> Cheers,
> >> Liz
> >> 
> >> 
> >> 
> >> 
> >> _______________________________________________
> >> testing-in-python mailing list
> >> [email protected]
> >> http://lists.idyll.org/listinfo/testing-in-python
> >> 
> 
import pytest

def pytest_generate_tests(metafunc):
    hasmyfixture = "myfixture" in metafunc.fixturenames
    paramlist = getattr(metafunc.function, "paramlist", None)

    if hasmyfixture:
        argvalues = ["std"]
        if paramlist:
            argvalues.append("pro")
        metafunc.parametrize("myfixture", argvalues, indirect=True)

    if paramlist:
        if isinstance(paramlist[0], dict):
            # old-style
            for p in paramlist:
                metafunc.addcall(funcargs=p)
        else:
            assert isinstance(paramlist[0], list)
            argnames = paramlist[0]
            argvalues = [d["argvalues"] for d in paramlist[1:]]
            metafunc.parametrize(argnames, argvalues)

def params(decolist):
    def wrapper(function):
        function.paramlist = decolist
        return function
    return wrapper

class SomeObject:
    def close(self):
        print "closing"

class SomeOtherObject(SomeObject):
    pass

@pytest.fixture
def myfixture(request):
    if request.param == 'std':
        myfix = SomeObject()
    elif request.param == 'pro':
        myfix = SomeOtherObject()
    else:
        assert 0, "unknown param"
    def fin():
        myfix.close()
    request.addfinalizer(fin)
    return myfix

@params([
    ['color', 'type'],
    { 'argvalues': [ 'blue', 'cat'] },
    { 'argvalues': ['pink', 'dog'] }
])
def test_example(myfixture, color, type):
    # this is the new test we want to add
    assert 0

def test_something(myfixture):
    # existing test which only uses std fixture
    assert 0

@params([
    {'arg1': 1, 'arg2': 2},
    {'arg1': 3, 'arg2': 5}
])
def test_old_style(arg1, arg2):
    # existing tests which don't use fixtures
    assert 0
_______________________________________________
Pytest-dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pytest-dev

Reply via email to