Passing (yield) fixtures as test parameters (with a temp directory)

后端 未结 3 1055
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-20 11:02

Question

Is it possible to pass yielding pytest fixtures (for setup and teardown) as parameters to test functions?

Context

I\'m testing an object th

3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-01-20 11:45

    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.

提交回复
热议问题