有没有关于如何使用FactoryGirl构建嵌套模型的Rails约定



BDD中有一部分我真的很困惑。我有各种不同的请求规格需要测试。具有以下结构:

  • 用户拥有许多产品
  • 产品具有多个价格级别(_M)
  • 价格级别有多个价格(_M)

我对如何使用FactoryGirl建立工厂感到困惑。我熟悉联想和特质的概念。我熟悉buildcreate的概念。但我不确定在什么情况下使用这些。

我能表达我困惑的最好方法就是举一些例子。

  • 我有一个测试User注册的请求规范。我不使用这里的工厂,原因很明显。这一点我理解。

  • 我有一个测试User创建新Products的请求规范。我create是一个用户工厂。我假设我需要在这里使用create而不是build,因为ProductsController中的CRUD方法对通过URL传递的id执行ARfind。如果我错了,请纠正我。

  • 我有一个请求规范来测试为Product添加不同的PriceLevels。这里我使用两个工厂:UserProduct

  • 我有一个请求规范来测试为UserProductPriceLevel添加不同的Prices。现在我有三个工厂:UserProductPriceLevel

如果Price有一个类似Currencyhas_and_belongs_to_many呢?工厂正在失去控制。

我想说,当我到达PriceLevel时,我想要一个能让我一次创建整个结构的工厂。然而,我不想每次都创建整个结构。此外,这些工厂可以自下而上或自上而下创建。

自下而上还是自上而下,哪种方式更好?我可以创建DRY代码,让我在一个工厂上有选择吗?还是一次创建整个shebang?我可以将after(:create)块包裹在性状中吗?我会在请求规范中使用buildcreate吗?

非常感谢您的关注!

首先,请求规范中的buildcreate

我通常在控制器规范中使用buildbuild_stubbed,方法是存根Model.find以返回构建的实例。然而,在Feature或Request规范中,通常应该避免嘲讽,所以在这里继续create

现在关于主要问题:

这听起来像是一个完美的特征案例。通常,基本工厂应该只具有生成有效模型所需的属性。然后,可以使用特性为常见或详细场景创建方便的"别名"。

您可以使用before(:create)来构建和分配相关模型。当FG最终在内部调用save/create时,Rails将处理保存所有内容。

示例:

factory :user do
# ...
trait :with_products do
before(:create) do |user|
user.products = build_list(:product, 3)
end
end
trait :with_priced_products do
before(:create) do |user|
user.products = build_list(:product, 3, :with_prices)
end
end
end
factory :product do
# ...
trait :with_prices do
before(:create) do |product|
product.prices = build_list(:price, 3)
end
end
end
factory :price

如果您想自定义在构建时添加了多少产品/价格,您只需添加ignored属性,并通过before hook的2-参数形式使用它们。

ignore do
number_of_products 3
end
before(:create) do |user, evaluator|
user.products = build_list(product, evaluator.number_of_products)
end

如果您希望能够在buildbuild_stubbed场景中使用这些with_特性,则必须在每种情况下使用正确的策略来复制相关挂钩。目前还没有简单的方法来说"使用与模型相同的策略添加一些关系",尽管这也是我自己的愿望清单。

最新更新