SCENARIO
我提取了一个名为Taggable
的关注。它是一个允许任何模型支持标记的模块。我已将此问题/模块包含在User
,Location
,Places
,Projects
等模型中。
我想为这个模块编写测试,但不知道从哪里开始。
问题
的 1。我可以对Taggable
关注点进行隔离测试吗?
在下面的示例中,测试失败,因为测试正在寻找dummy_class table
。由于has_many
中的Taggable
代码,我假设它正在这样做,因此它希望'DummyClass'
成为ActiveRecord对象。
# /app/models/concerns/taggable.rb
module Taggable
extend ActiveSupport::Concern
included do
has_many :taggings, :as => :taggable, :dependent=> :destroy
has_many :tags, :through => :taggings
end
def tag(name)
name.strip!
tag = Tag.find_or_create_by_name(name)
self.taggings.find_or_create_by_tag_id(tag.id)
end
end
# /test/models/concerns/taggable_test.rb
require 'test_helpers'
class DummyClass
end
describe Taggable do
before do
@dummy = DummyClass.new
@dummy.extend(Taggable)
end
it "gets all tags" do
@dummy.tag("dummy tag")
@dummy.tags.must_be_instance_of Array
end
end
我的一部分认为,如果我只测试一个包含此模块的模型,如User
那就足够了。但我一直在读,你应该单独测试模块。
寻找关于正确方法的一些指导/策略。
答案 0 :(得分:5)
我建议让DummyClass
成为一个普通的ActiveRecord::Base
孩子,除了include Taggable
之外只有很少的自定义代码,这样你就可以尽可能地隔离你的关注模块但仍然存在AR类。避免使用像User
这样的“真正”类仍然会使您与这些类中的任何其他代码隔离开来,这看起来很有价值。
这样的事情:
class DummyClass < ActiveRecord::Base; end
describe Taggable do
before do
@dummy_class = DummyClass.new
end
...
end
由于您的DummyClass
可能需要与DB实际交互以测试关联等内容,因此您可能需要在测试期间在数据库中创建临时表。 temping Ruby gem可能能够提供帮助,因为它旨在创建临时ActiveRecord模型及其底层数据库表。
Temping 允许您创建由临时SQL表支持的任意ActiveRecord模型,以便在测试中使用。如果您正在测试一个混合到ActiveReord模型中的模块而不转发具体类,则可能需要执行此类操作。
答案 1 :(得分:2)
我选择使用ActiveRecord Tableless而不是Temping gem,这似乎有点过时了。
我将我的测试设置为Stuart M与answer完全相同,但包含了我的DummyClass中所需的has_no_table
辅助方法和列。
class DummyClass < ActiveRecord::Base
# Use ActiveRecord tableless
has_no_table
# Add table columns
column :name, :string
# Add normal ActiveRecord validations etc
validates :name, :presence => true
end
这适用于我需要测试的内容,这是一个使用一些其他方法扩展ActiveRecord::Base
的模块,但我没有尝试使用任何has_many
关联,所以它仍然可能无法帮助用你想测试的东西。
答案 2 :(得分:1)
以下是我类似问题的解决方案:
describe Taggable do
subject { mock_model('User').send(:extend, Taggable) }
it { should have_many(:tags) }
...
describe "#tag" do
...
end
end
实际上mock_model('User')
可以模拟系统中任何现有的模型。
这不是一个理想的解决方案,但至少它是清楚的,并嘲笑一切。
注意:mock_model
(AR模拟)在rspec 3.0中被提取到rspec-activemodel-mocks。
此外,您还需要使用shoulda-matchers进行关联匹配。
答案 3 :(得分:0)