BDD中有一部分我真的很困惑。我有各种不同的请求规格需要测试。具有以下结构:
- 用户拥有许多产品
- 产品具有多个价格级别(_M)
- 价格级别有多个价格(_M)
我对如何使用FactoryGirl建立工厂感到困惑。我熟悉联想和特质的概念。我熟悉build
和create
的概念。但我不确定在什么情况下使用这些。
我能表达我困惑的最好方法就是举一些例子。
-
我有一个测试
User
注册的请求规范。我不使用这里的工厂,原因很明显。这一点我理解。 -
我有一个测试
User
创建新Products
的请求规范。我create
是一个用户工厂。我假设我需要在这里使用create
而不是build
,因为ProductsController
中的CRUD方法对通过URL传递的id执行ARfind
。如果我错了,请纠正我。 -
我有一个请求规范来测试为
Product
添加不同的PriceLevels
。这里我使用两个工厂:User
和Product
。 -
我有一个请求规范来测试为
User
的Product
的PriceLevel
添加不同的Prices
。现在我有三个工厂:User
,Product
,PriceLevel
。
如果Price
有一个类似Currency
的has_and_belongs_to_many
呢?工厂正在失去控制。
我想说,当我到达PriceLevel
时,我想要一个能让我一次创建整个结构的工厂。然而,我不想每次都创建整个结构。此外,这些工厂可以自下而上或自上而下创建。
自下而上还是自上而下,哪种方式更好?我可以创建DRY代码,让我在一个工厂上有选择吗?还是一次创建整个shebang?我可以将after(:create)
块包裹在性状中吗?我会在请求规范中使用build
与create
吗?
非常感谢您的关注!
首先,请求规范中的build
与create
:
我通常在控制器规范中使用build
或build_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
如果您想自定义在构建时添加了多少产品/价格,您只需添加ignore
d属性,并通过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
如果您希望能够在build
或build_stubbed
场景中使用这些with_
特性,则必须在每种情况下使用正确的策略来复制相关挂钩。目前还没有简单的方法来说"使用与模型相同的策略添加一些关系",尽管这也是我自己的愿望清单。