测试使用ActiveRecord的问题/模块

场景我提取了一个名为Taggable 。 它是一个允许任何模型支持标记的模块。 我已将此问题/模块包含在UserLocationLocationProjects

我想为这个模块编写测试,但不知道从哪里开始。


1.我可以对Taggable问题进行隔离测试吗?
在下面的示例中,测试失败,因为测试正在查找dummy_class table 。 我假设它正在这样做是因为Taggable中的has_many代码,因此它希望'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那样足够的测试。 但我一直在读,你应该单独测试模块。

寻找关于正确方法的一些指导/策略。

我建议将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交互以测试关联之类的事情,因此您可能需要在测试期间在DB中创建临时表。 临时Ruby gem可能能够提供帮助,因为它旨在创建临时ActiveRecord模型及其底层数据库表。

Temping允许您创建由临时SQL表支持的任意ActiveRecord模型,以便在测试中使用。 如果您正在测试一个混合到ActiveReord模型中的模块而不转发具体类,则可能需要执行此类操作。

我使用ActiveRecord Tableless而不是Temping gem,这似乎有点过时了。

我设置的测试与Stuart M在答案中完全相同,但包括了我的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关联,所以它仍然可能对你想要测试的内容没有帮助。

这是我的类似问题的解决方案:

 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 mock_model )被提取到rspec 3.0中的rspec-activemodel-mocks 。
此外,您还需要使用shoulda-matcher进行关联匹配。

正如在@StuartM的回答中所建议的,使用临时gem对我有用:

 # test.rb/spec.rb Temping.create :dummy_class do include Taggable end describe Taggable do before do @dummy = DummyClass.new end ... end