2014-02-05 155 views
12

比方说,我有一个简单的灯具,如以下(使用pytest-Django的,但我认为它应该适用于pytest以及):多个副本

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

这个伟大的工程时我的测试需要一个MyModel实例。但是如果我需要两个(或三个或四个)呢?我希望每个实例都是独特的,但要以相同的方式进行设置。

我可以复制/粘贴代码并重命名灯具功能,但看起来不够雅致。

同样,我曾尝试:

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

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

然而,这些出现的回归为MyModel的同一个实例。

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

或者我是否以错误的方式处理这件事?

回答

17

我的方法可能会创建一个夹具,可以生成你的对象:

@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:另外请注意没有必要为拉姆达在终结者)

+1

1)不需要在拉姆达终结良好的通话。 2)我喜欢你的方法。我实际上是使用Factory Boy来创建这些模型,所以我认为我甚至不需要为每个模型创建工厂固定装置。但是我无法继承ModelFactory以递归添加子工厂的终结器,所以我想我会使用您的方法作为停止缺口。谢谢! –

+1

为了将来的参考,我使用finalizer的唯一原因是pytest-django没有在两次测试之间清理数据库,因为它不支持多个数据库(另请参阅https://github.com/pelme/pytest_django/issues/ 76)。对于上面描述的问题类型,我衷心推荐使用带有pytest-django的FactoryBoy。 –

0

我很晚才到达这个问题......但是,使用参数化夹具,并简单地返回你想要复制的夹具似乎也工作。

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 ===========================================