我正在使用Rspec和Capybara编写集成测试。我注意到在测试activerecord选项的创建时,我经常需要执行相同的代码。
例如:
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并填写面向用户的表单要简单得多。
我已经尝试定义一个创建新记录的函数,但由于某种原因这感觉不对。对此最好的做法是什么?
答案 0 :(得分:9)
这里有几种不同的方式。首先,在这两种情况下,您都可以在describe或context块下对示例块进行分组,如下所示:
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 helper,我觉得它更具可读性。您可以查看有关它的更多信息here。
答案 1 :(得分:7)
您的要求的最佳实践是使用Factory Girl从蓝图创建定义公共属性的记录,并使用database_cleaner在不同的测试/规范中清理数据库。
并且从不在不同的规范中保持状态(例如创建的记录),这将导致依赖规范。您可以使用rspec的--order rand
选项来发现这种依赖关系。如果您的规格随机失败,则会遇到此类问题。
答案 2 :(得分:2)
鉴于标题(...重用Rspec中的代码),我建议在“Ruby on Rails教程”中阅读RSpec custom matchers。
迈克尔·哈特尔建议两种规格重复的解决方案:使用这些东西有助于将测试与实现分离。
除了这些,我建议(如Fabio所说)使用FactoryGirl。
答案 3 :(得分:1)
您可以查看我的示例导轨项目。你可以在那里找到:https://github.com/lucassus/locomotive
spec/support
)shared_examples
答案 4 :(得分: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