5

我正在使用 Rspec 和 Capybara 编写集成测试。我注意到,在测试活动记录选项的创建时,我经常必须执行相同的代码位。

例如:

it "should create a new instance" do
  # I create an instance here
end

it "should do something based on a new instance" do
  # I create an instance here
  # I click into the record and add a sub record, or something else
end

问题似乎是 ActiveRecord 对象不会在测试中保持不变,但是 Capybara 默认情况下会在规范中维护相同的会话(怪异)。

我可以模拟这些记录,但由于这是一个集成测试,并且其中一些记录非常复杂(它们有图像附件等等),因此使用 Capybara 并填写面向用户的表单要简单得多。

我尝试定义一个创建新记录的函数,但由于某种原因感觉不对。这方面的最佳做法是什么?

4

5 回答 5

10

有几种不同的方式可以去这里。首先,在这两种情况下,您都可以将示例块分组到描述块或上下文块下,如下所示:

describe "your instance" do
  it "..." do
    # do stuff here
  end

  it "..." do
    # do other stuff here
  end
end

然后,在 describe 或 context 块中,您可以设置可在所有示例中使用的状态,如下所示:

describe "your instance" do
  # run before each example block under the describe block
  before(:each) do
    # I create an instance here
  end

  it "creates a new instance" do
    # do stuff here
  end

  it "do something based on a new instance" do
    # do other stuff here
  end
end

作为 before(:each) 块的替代方法,您还可以使用 let 助手,我发现它更具可读性。你可以在这里看到更多关于它的信息。

于 2012-05-23T22:07:13.447 回答
7

满足您要求的最佳实践是使用Factory Girl从定义通用属性的蓝图创建记录,并使用database_cleaner跨不同测试/规范清理数据库。

并且永远不要在不同的规范中保持状态(例如创建的记录),这将导致依赖规范。--order rand您可以使用rspec 选项发现这种依赖关系。如果您的规格随机失败,您就会遇到此类问题。

于 2012-05-23T22:02:24.337 回答
3

鉴于标题(...在 Rspec 中重用代码),我建议阅读“Ruby on Rails 教程”中的RSpec 自定义匹配器。

Michael Hartl 提出了两种解决规范重复的方法:

  1. 定义常用操作的辅助方法(例如登录用户)
  2. 定义自定义匹配器

使用这些东西有助于将测试与实现分离。

除了这些,我建议(如法比奥所说)使用 FactoryGirl。

于 2012-05-27T00:10:31.853 回答
1

您可以查看我的示例 rails 项目。你可以在那里找到:https ://github.com/lucassus/locomotive

  • 如何使用 factory_girl
  • 自定义匹配器和宏的一些示例(在spec/support
  • 如何使用shared_examples
  • 最后如何使用非常好的 shoulda-macros
于 2012-05-27T21:49:04.010 回答
0

我会结合使用 factory_girl 和 Rspec 的 let 方法:

describe User do
  let(:user) { create :user } # 'create' is a factory_girl method, that will save a new user in the test database

  it "should be able to run" do
    user.run.should be_true
  end

  it "should not be able to walk" do
    user.walk.should be_false
  end
end


# spec/factories/users.rb
FactoryGirl.define do
  factory :user do
    email { Faker::Internet.email }
    username { Faker::Internet.user_name }
  end
end

这使您可以做如下出色的事情:

describe User do
  let(:user) { create :user, attributes }
  let(:attributes) { Hash.new }

  it "should be able to run" do
    user.run.should be_true
  end

  it "should not be able to walk" do
    user.walk.should be_false
  end

  context "when user is admin" do
    let(:attributes) { { admin: true } }
    it "should be able to walk" do
      user.walk.should be_true
    end
  end
end
于 2013-08-14T06:52:18.960 回答