Is it possible to pass yielding pytest fixtures (for setup and teardown) as parameters to test functions?
I\'m testing an object th
I see your problem but I'm not sure about the solution. The problem:
Your functions thing1 and thing2 contain yield statements. When you call a function like that, the returned value is a "generator object." It's an iterator - a sequence of values, which is of course not the same thing as the first value of yield
, or any one particular value.
Those are the objects being passed to your test_attr
function. The test environment is doing that for you automagically, or at least I think that's how it works.
What you really want is the object created in your yield
expression, in other words, Thing(datadir=datadir, errorfile=errorfile)
. There are three ways to get a generator to emit its individual values: by calling next(iter)
, by calling iter.__next__()
or by using the iterator in a loop with an in
expression.
One possibility is to iterate the generator once. Like this:
def test_attr(thing):
first_thing = next(thing)
print(first_thing.datadir)
assert os.path.exists(first_thing.datadir)
first_thing
will be the object you want to test, i.e., Thing(datadir=datadir, errorfile=errorfile)
.
But this is only the first hurdle. The generator function is not finished. Its internal "program counter" is just after the yield
statement. So you haven't exited the context manager and haven't deleted your temporary directory yet. To do this you must call next(thing)
again and catch a StopIteration
exception.
Alternatively I think this will work:
def test_attr(thing):
for a_thing in thing:
print(a_thing.datadir)
assert os.path.exists(a_thing.datadir)
The in
expression loops through all the items in the iterator (there's only one) and exits gracefully when StopIteration occurs. The function exits from the context manager and your work is done.
To me it's an open question whether this makes your code more or less readable and maintainable. It's a bit clumsy.