【问题标题】:Multiple copies of a pytest fixturepytest 夹具的多个副本
【发布时间】:2014-03-02 06:32:36
【问题描述】:

假设我有一个像下面这样的简单夹具(使用 pytest-django,但它也适用于 pytest):

@pytest.fixture
def my_thing(request, db):
    thing = MyModel.objects.create()
    request.addfinalizer(lambda: thing.delete())
    return thing

当我的测试需要 MyModel 的单个实例时,这非常有用。但是如果我需要两个(或三个或四个)呢?我希望每个实例都是不同的,但要以相同的方式设置。

我可以复制/粘贴代码并重命名fixture函数,但这似乎不太优雅。

同样,我也试过:

@pytest.fixture
def my_thing_1(my_thing):
    return my_thing

@pytest.fixture
def my_thing_2(my_thing):
    return my_thing

但是,它们中的每一个似乎都返回了相同的 MyModel 实例。

有没有办法使用 pytest 的内置功能来做我想做的事?或者,我可以将我的夹具的设置/拆卸移到辅助函数中,这样我就不会复制太多代码。

还是说我做错了事?

【问题讨论】:

    标签: python django testing pytest


    【解决方案1】:

    我的方法可能是创建一个可以生成您的对象的夹具:

    @pytest.fixture
    def thing(request, db):
        class ThingFactory(object):
            def get(self):
                thing = MyModel.objects.create()
                request.addfinalizer(thing.delete)
                return thing
        return ThingFactory()
    
    def test_thing(thing):
        thing1 = thing.get()
        thing2 = thing.get()
    

    显然你可以让.get() 接受一个论点等等。

    (PS:另请注意,终结器中不需要 lambda)

    【讨论】:

    • 1) 很好地呼吁终结器中不需要 lambda。 2)我喜欢你的方法。我实际上是在使用 Factory Boy 来创建这些模型,所以我认为理想情况下我什至不需要为每个模型创建工厂夹具。但是我在继承 ModelFactory 以递归地为 SubFactories 添加终结器时遇到了麻烦,所以我想我会用你的方法作为权宜之计。谢谢!
    • 为了将来参考,我使用终结器的唯一原因是因为 pytest-django 没有在测试之间清理数据库,因为它不支持多个数据库(另请参阅github.com/pelme/pytest_django/issues/76)。对于我上面描述的问题类型,我全心全意地推荐使用 FactoryBoy 和 pytest-django。
    • 在这种情况下如何定义拆解逻辑?特别是,我想确保即使测试失败/引发异常也会发生拆除。
    • @ingomueller.net 使用withcontextlib.ExitStack()as stack,让工厂,让.get()stack.callback()注册析构函数
    • @clacke:完美,正是我想要的!很好的模式也适用于其他情况......谢谢!
    【解决方案2】:

    我很晚才知道这个问题......但是,使用参数化的夹具并简单地返回您想要复制的夹具似乎也可以。

    import pytest
    import random
    
    @pytest.fixture
    def name():
        return random.randint(0, 10)
    
    
    @pytest.fixture(params=[0, 1])
    def parametrized_name(request, name):
        return name
    
    
    def test_something(parametrized_name):
        print "Testing with name: " + str(parametrized_name)
    

    如果您运行上述测试,您会得到 2 个不同的“名称”固定装置

    $ pytest -s blah.py
    ============================================= test session starts ==============================================
    platform linux2 -- Python 2.7.14, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
    rootdir: /home/bsquizza/repos/blah/tests, inifile:
    collected 2 items                                                                                              
    
    blah.py Testing with name: 7
    .Testing with name: 10
    .                                                                                               [100%]
    
    =========================================== 2 passed in 0.01 seconds ===========================================
    

    【讨论】:

    • 这无济于事 - 问题是关于在同一个测试中获取两个不同的实例 - 你在这里所拥有的会生成两个不同的测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    • 2018-01-31
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2022-09-23
    相关资源
    最近更新 更多