下面是另一个例子(使用Factorygirl的“创造”方法”和shared_examples_for)
关注规范
#spec/support/concerns/commentable_spec
require 'spec_helper'
shared_examples_for 'commentable' do
let (:model) { create (described_class.to_s.underscore) }
let (:user) { create (:user) }
it 'has comments' do
expect { model.comments }.to_not raise_error
end
it 'comment method returns Comment object as association' do
model.comment(user, "description")
expect(model.comments.length).to eq(1)
end
it 'user can make multiple comments' do
model.comment(user, "description")
model.comment(user, "description")
expect(model.comments.length).to eq(2)
end
end
commentable关注
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
def comment(user, description)
Comment.create(commentable_id: self.id,
commentable_type: self.class.name,
user_id: user.id,
description: description
)
end
end
and restraunt_spec可能看起来像这样(我n OT Rspec的大师,所以不要认为我写的规格的方式是很好的 - 最重要的事情是开头):
require 'rails_helper'
RSpec.describe Restraunt, type: :model do
it_behaves_like 'commentable'
describe 'with valid data' do
let (:restraunt) { create(:restraunt) }
it 'has valid factory' do
expect(restraunt).to be_valid
end
it 'has many comments' do
expect { restraunt.comments }.to_not raise_error
end
end
describe 'with invalid data' do
it 'is invalid without a name' do
restraunt = build(:restraunt, name: nil)
restraunt.save
expect(restraunt.errors[:name].length).to eq(1)
end
it 'is invalid without description' do
restraunt = build(:restraunt, description: nil)
restraunt.save
expect(restraunt.errors[:description].length).to eq(1)
end
it 'is invalid without location' do
restraunt = build(:restraunt, location: nil)
restraunt.save
expect(restraunt.errors[:location].length).to eq(1)
end
it 'does not allow duplicated name' do
restraunt = create(:restraunt, name: 'test_name')
restraunt2 = build(:restraunt, name: 'test_name')
restraunt2.save
expect(restraunt2.errors[:name].length).to eq(1)
end
end
end
这显然是最好的答案。在Dummy情况下可以显式地进行测试,并在父类的规范中测试相同的API。这在处理任何“灵活”的API时都有所不同(阅读:method_missing)。只有一些情况只有在“真实”(非虚拟)类中使用时才能想到,并且共享示例在每种必要情况下都会很好地执行代码。 – winfred 2013-07-29 17:36:47
当你的模块添加动态属性时,这会崩溃。假设你的模块允许类方法:'allow_upload:csv',它增加了'csv_file_path'和'csv_file_size'等方法。但是你有另一个模型调用上传的文件':attachment'。现在你的“作为上传”规范将失败,因为一个是添加'csv_file_path',另一个'attachment_file_path'。基于这个原因,我觉得在很多情况下,最好使用一个虚拟类来测试模块的行为,就像@Martijn的回答 – nzifnab 2014-05-07 21:24:00
@nzifnab一样清楚,模块没有添加方法,子类是明确的。这里的共享示例是否合适是针对代码库的判断调用。但是,您仍然可以以这种方式使用它们。有可能将信息传递给他们,就像你在电话中一样:'it_behaves_like'充当上传',:csv' – 2014-05-08 03:36:00