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

时间:2014-01-09 18:43:14

标签: ruby-on-rails-3 bdd factory-bot

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

  • 用户has_many产品
  • 产品has_many PriceLevels
  • PriceLevel has_many价格

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

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

  • 我有一个请求规范来测试User注册。出于显而易见的原因,我不在这里使用工厂。我理解这一点。

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

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

  • 我有一个请求规范,用于测试为Product的{​​{1}} Prices添加不同的User。现在我最多有3家工厂:ProductPriceLevelUser

现在如果Product的{​​{1}}有PriceLevel之类的内容怎么办?工厂失控。

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

哪种方式更好,自下而上或自上而下?我可以创建干燥代码,让我可以选择单个工厂或立即创建整个shebang吗?我可以将has_and_belongs_to_many块包裹在特征中吗?我是否会在请求规范中使用Currency vs PriceLevel

非常感谢您的关注!

1 个答案:

答案 0 :(得分:1)

首先,请求规范中的buildcreate

我通常在控制器规范中使用buildbuild_stubbed,通过存根Model.find来返回构建的实例。但是,在功能或请求规范中应该避免使用模拟,因此请继续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个属性,并通过前挂钩的双参数形式使用它们。

ignore do
  number_of_products 3
end

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

如果您希望能够在with_build方案中使用这些build_stubbed特征,则必须在每种情况下使用正确的策略复制相关的钩子。目前还没有简单的方法可以说“使用与模型相同的策略添加一些关系”,尽管这也是我自己的愿望清单项目。