问题描述:

I apologize in advance for repeating the word parameter 1000 times. My use case is as follows.

I'm using pytest to test a parser that parses fields out of product pages from an online shop.

I have parametrized a fixture, so that each fixture imports data for one product. By data, I mean the HTML source code and a list of fields with their expected values. Down the line I have a parametrized test that takes a list of tuples (field, expected value), so that each field gets its own test.

Basically, the "bare bones" problem would like something like this:

from pytest import fixture, mark

products = [

{

'text': 'bla bla',

'fields': [('bla', 0), ('foo', -1)]

},

{

'text': 'foo bar',

'fields': [('bla', -1), ('foo', 0), ('bar', 4)]

}

]

@fixture(params=products)

def product(request):

return request.param

@mark.parametrize('field_key, field_value', product['fields'])

def test_parser(product, field_key, field_value):

assert product['text'].find(field_key) == field_value

In the context of the @mark.parametrize decorator, product isn't interpreted as a fixture, so pytest returns:

TypeError: 'function' object has no attribute '__getitem__'

There's lot of introspection magic going on with pytest and I'm having trouble finding a solution. I had a look at this question but this is not quite what I want. Is there a way to achieve this? Thanks.

网友答案:

I don't think you need fixtures to achieve your goal.

Given your example data, this is a possible way:

from pytest import mark


products = [
    {
        'text': 'bla bla',
        'fields': [('bla', 0), ('foo', -1)]
    },
    {
        'text': 'foo bar',
        'fields': [('bla', -1), ('foo', 0), ('bar', 4)]
    }
]

possible_params = []
for product in products:  # Iterate over the products to build all desired invocations
    for field_key, field_value in product['fields']:
        possible_params.append((product['text'], field_key, field_value))

@mark.parametrize('text,field_key,field_value', possible_params)
def test_parser(text, field_key, field_value):
    assert text.find(field_key) == field_value
网友答案:

I was able to get this to run (in Python3), although the tests fail:

#!python3
from pytest import fixture, mark

Products = [
    {
        'text':   'bla bla',
        'fields': [('bla', 0), ('foo', -1)]
    },
    {
        'text':   'foo bar',
        'fields': [('bla', -1), ('foo', 0), ('bar', 1)]
    }
]

@fixture(scope="module",
        params=[(prod['text'], *tpl) for prod in Products for tpl in prod['fields']])
def product(request):
    return request.param


def test_parser(product):
    haystack,needle,index = product
    assert haystack.find(needle) == index
相关阅读:
Top