2013-04-07 66 views
11

情景 我已經提取的關注稱爲Taggable。這是一個允許任何模型支持標記的模塊。我已將此關注/模塊納入UserLocation,Places,Projects等模型中。測試關注/模塊使用的ActiveRecord

我想寫這個模塊的測試,但不知道從哪裏開始。

問題
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這足夠測試的模型。但我一直在讀,你應該單獨測試模塊。

尋找正確方法的一些指導/策略。

+0

您使用'@ dummy_class',然後使用'@ dummy'。我認爲這是無意的。 – RubeOnRails 2013-09-16 20:16:07

回答

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互動,測試之類的社團,你可能需要在測試期間創建數據庫臨時表。 Ruby gem可以幫助解決這個問題,因爲它的目的是創建臨時的ActiveRecord模型及其底層數據庫表。

臨時工允許您創建通過在試驗中使用的臨時SQL表支持任意的ActiveRecord模型。如果您正在測試一個要混入ActiveReord模型而不會在具體類中繼承的模塊,則可能需要執行此類操作。

+1

所以我之前嘗試過你的方法,但是當我運行我的測試時,它一直在想我有一個'dummy_classes'表。 ActiveRecord :: StatementInvalid:找不到表'dummy_classes' – alenm 2013-04-07 22:01:22

+0

您可能會發現[temping](https://github.com/jpignata/temping)gem有用,請參閱我上面更新的回答 – 2013-04-07 22:05:08

+0

感謝您提供關於臨時寶石的建議。但是我想爲什麼要經歷使用這個gem的過程,當我可以在一個像「User」這樣的真正的ActiveRecord類中測試模塊時。也許這是正確的方法?如果這個模塊確實需要ActiveRecord然後測試它。儘管是偉大的寶石。 – alenm 2013-04-08 00:20:43

0

正如@ StuartM的answer建議,使用temping寶石爲我工作:

# test.rb/spec.rb 
Temping.create :dummy_class do 
    include Taggable 
end 

describe Taggable do 
    before do 
    @dummy = DummyClass.new 
    end 
    ... 
end 
+0

請注意,我還沒有'DummyClass.create'工作,但不幸的是與臨時的寶石 – SuckerForMayhem 2014-08-01 18:49:02

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作爲關聯匹配器。

2

我去的時候使用的是ActiveRecord Tableless而不是Temping寶石,這個寶石看起來有點過時了。

我設置了我的測試,與Stuart Manswer完全相同,但在我的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協會嘗試它,所以它可能仍然無法與你想要的幫助去測試。