传递(产量)夹具作为测试参数(带有临时目录) [英] Passing (yield) fixtures as test parameters (with a temp directory)

查看:53
本文介绍了传递(产量)夹具作为测试参数(带有临时目录)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以将产生的 pytest 固定装置(用于设置和拆卸)作为参数传递给测试函数?

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

我正在测试一个对象,该对象从/向单个目录中的文件读取和写入数据.该目录的路径被保存为对象的属性.

I'm testing an object that reads and writes data from/to files in a single directory. That path of that directory is saved as an attribute of the object.

我遇到了以下问题:

  1. 在我的测试中使用临时目录;和
  2. 确保在每次测试后删除该目录.

示例

考虑以下内容 (test_yieldfixtures.py):

Example

Consider the following (test_yieldfixtures.py):

import pytest, tempfile, os, shutil
from contextlib import contextmanager
    
@contextmanager
def data():
    datadir = tempfile.mkdtemp()  # setup
    yield datadir
    shutil.rmtree(datadir)        # teardown
    
class Thing:
    def __init__(self, datadir, errorfile):
        self.datadir = datadir
        self.errorfile = errorfile

    
@pytest.fixture
def thing1():
    with data() as datadir:
        errorfile = os.path.join(datadir, 'testlog1.log')
        yield Thing(datadir=datadir, errorfile=errorfile)

@pytest.fixture
def thing2():
    with data() as datadir:
        errorfile = os.path.join(datadir, 'testlog2.log')
        yield Thing(datadir=datadir, errorfile=errorfile)

@pytest.mark.parametrize('thing', [thing1, thing2])
def test_attr(thing):
    print(thing.datadir)
    assert os.path.exists(thing.datadir)

运行 pytest test_yieldfixtures.py 输出以下内容:

Running pytest test_yieldfixtures.py outputs the following:

================================== FAILURES ===================================
______________________________ test_attr[thing0] ______________________________

thing = <generator object thing1 at 0x0000017B50C61BF8>

    @pytest.mark.parametrize('thing', [thing1, thing2])
    def test_attr(thing):
>        print(thing.datadir)
E       AttributeError: 'function' object has no attribute 'props'

test_mod.py:39: AttributeError

好的.所以夹具函数没有我的类的属性.很公平.

OK. So fixture functions don't have a the properties of my class. Fair enough.

函数没有属性,所以我尝试调用该函数来实际获取对象.然而,那只是

A function won't have the properties, so I tried calling that functions to actually get the objects. However, that just

@pytest.mark.parametrize('thing', [thing1(), thing2()])
def test_attr(thing):
    print(thing.props['datadir'])
    assert os.path.exists(thing.get('datadir'))

结果:

================================== FAILURES ===================================
______________________________ test_attr[thing0] ______________________________

thing = <generator object thing1 at 0x0000017B50C61BF8>

    @pytest.mark.parametrize('thing', [thing1(), thing2()])
    def test_attr(thing):
>       print(thing.datadir)
E       AttributeError: 'generator' object has no attribute 'props'

test_mod.py:39: AttributeError

尝试 2

我还尝试在 thing1/2 固定装置中使用 return 而不是 yield ,但这使我脱离了 data 上下文管理器并删除目录:

Attempt 2

I also tried using return instead of yield in the thing1/2 fixtures, but that kicks me out of the data context manager and removes the directory:

================================== FAILURES ===================================
______________________________ test_attr[thing0] ______________________________

thing = <test_mod.Thing object at 0x000001C528F05358>

    @pytest.mark.parametrize('thing', [thing1(), thing2()])
    def test_attr(thing):
        print(thing.datadir)
>       assert os.path.exists(thing.datadir)

结束

重申这个问题:有没有办法将这些fixtures作为参数传递并维护临时目录的清理?

Closing

To restate the question: Is there anyway to pass these fixtures as parameters and maintain the cleanup of the temporary directory?

推荐答案

尝试将您的 data 函数/生成器变成一个装置.然后使用 request.getfixturevalue() 动态运行命名装置.

Try making your data function / generator into a fixture. Then use request.getfixturevalue() to dynamically run the named fixture.

import pytest, tempfile, os, shutil
from contextlib import contextmanager

@pytest.fixture # This works with pytest>3.0, on pytest<3.0 use yield_fixture
def datadir():
    datadir = tempfile.mkdtemp()  # setup
    yield datadir
    shutil.rmtree(datadir)        # teardown

class Thing:
    def __init__(self, datadir, errorfile):
        self.datadir = datadir
        self.errorfile = errorfile


@pytest.fixture
def thing1(datadir):
    errorfile = os.path.join(datadir, 'testlog1.log')
    yield Thing(datadir=datadir, errorfile=errorfile)

@pytest.fixture
def thing2(datadir):
    errorfile = os.path.join(datadir, 'testlog2.log')
    yield Thing(datadir=datadir, errorfile=errorfile)

@pytest.mark.parametrize('thing_fixture_name', ['thing1', 'thing2'])
def test_attr(request, thing):
    thing = request.getfixturevalue(thing) # This works with pytest>3.0, on pytest<3.0 use getfuncargvalue
    print(thing.datadir)
    assert os.path.exists(thing.datadir)

再进一步,您可以像这样对 thing 装置进行参数化:

Going one step futher, you can parametrize the thing fixtures like so:

class Thing:
    def __init__(self, datadir, errorfile):
        self.datadir = datadir
        self.errorfile = errorfile

@pytest.fixture(params=['test1.log', 'test2.log'])
def thing(request):
    with tempfile.TemporaryDirectory() as datadir:
        errorfile = os.path.join(datadir, request.param)
        yield Thing(datadir=datadir, errorfile=errorfile)

def test_thing_datadir(thing):
    assert os.path.exists(thing.datadir)

这篇关于传递(产量)夹具作为测试参数(带有临时目录)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆