Ste*_*ven 7 python unit-testing factory-boy
我正在尝试使用 Factoryboy 在创建时指定长度的对象中创建一个列表。
我可以创建列表,但是由于提供的长度/大小的惰性性质,每次尝试创建具有指定长度的列表都会导致问题。
这是我到目前为止所拥有的:
class FooFactory(factory.Factory):
class Meta:
model = command.Foo
foo_uuid = factory.Faker("uuid4")
bars = factory.List([
factory.LazyAttribute(lambda o: BarFactory()
for _ in range(3))
])
Run Code Online (Sandbox Code Playgroud)
这将创建一个包含 3 个随机条的列表。我尝试过使用 Params 和排除的组合,但由于 range 需要一个 Int,并且 int 直到稍后才会延迟加载,因此会导致错误。
我想要类似于如何使用 post_ Generation 生成一对多关系的东西,即。
foo = FooFactory(number_of_bars=5)
Run Code Online (Sandbox Code Playgroud)
有人有这样的运气吗?
为此需要两件事:
参数
和LazyAttribute
(链接指向其文档,以获取更多详细信息)。
参数就像工厂属性,不会传递给将创建的实例。在这种情况下,它们提供了一种参数化 s 列表长度的方法Bar。
但是为了使用参数来自定义工厂中的字段,我们需要访问self,即正在构建的实例。我们可以使用 来实现这一点LazyAttribute,这是一个带有一个参数的函数的声明:正在构建的对象。正是我们所需要的。
因此问题中的片段可以重写如下:
class FooFactory(factory.Factory):
class Meta:
model = command.Foo
class Params:
number_of_bars = 1
foo_uuid = factory.Faker("uuid4")
bars = factory.LazyAttribute(lambda self: [BarFactory()] * self.number_of_bars)
Run Code Online (Sandbox Code Playgroud)
并像这样使用:
foo = FooFactory(number_of_bars=3)
Run Code Online (Sandbox Code Playgroud)
如果number_of_bars未提供参数,则1使用默认值。
遗憾的是,我们在这里能做的事情有一些限制。
在定义另一个工厂时使用一个工厂的首选方式是 via
SubFactory。这是首选的原因有两个:
第一个意味着,如果我们过去SubFactory构建BarinFooFactory
并FooFactory使用FooFactory.createor进行调用FooFactory.build,子Bar工厂将尊重这一点并使用相同的策略。总之,构建策略仅构建实例,而创建策略构建实例并将其保存到正在使用的持久存储中,例如数据库,因此尊重此选择很重要。请参阅文档
了解更多详细信息。
第二个意思是我们可以直接自定义Bar调用时的属性FooFactory。例如:
foo = FooFactory(bar__id=2)
Run Code Online (Sandbox Code Playgroud)
会将idof 的值bar设置foo为,2而不是Bar子工厂默认生成的值。
但我找不到使用方法SubFactory 和动态长度Params。据我所知,无法在 FactoryBoy 期望的上下文中访问参数的值SubFactory。问题在于,允许我们访问正在构建的对象的声明总是期望返回最终值,而不是稍后调用另一个工厂。这意味着,在上面的例子中,如果我们改写:
class FooFactory(factory.Factory):
# ... rest of the factory
bars = factory.LazyAttribute(lambda self: [factory.SubFactory(BarFactory)] * self.number_of_bars)
Run Code Online (Sandbox Code Playgroud)
然后这样称呼它
foo = FooFactory(number_of_bars=3)
Run Code Online (Sandbox Code Playgroud)
将导致 afoo具有 3 的列表BarFactory,foo.bars而不是 3 的列表Bar。使用SelfAttribute,这是一种引用正在构建的实例的另一个属性的方法,也不起作用,因为它不会在声明中的其余表达式之前进行评估,如下所示:
class FooFactory(factory.Factory):
# ... rest of the factory
bars = factory.List([factory.SubFactory(BarFactory)] * SelfAttribute("number_of_bars"))
Run Code Online (Sandbox Code Playgroud)
这就引发了TypeError: can't multiply sequence by non-int of type 'SelfAttribute'. 一种可能的解决方法是提前调用BarFactory并将其传递给FooFactory:
number_of_bars = 3
bars = BarFactory.create_batch(number_of_bars)
foo = FooFactory(bars=bars)
Run Code Online (Sandbox Code Playgroud)
但这肯定没有那么好。
我最近发现的另一件事是RelatedFactoryList。但这仍然是实验性的,而且似乎没有办法访问参数。此外,由于它是在基础工厂之后生成的,因此如果实例构造函数需要该属性作为参数,它也可能不起作用。
| 归档时间: |
|
| 查看次数: |
2492 次 |
| 最近记录: |