2013-03-29 37 views
2

我有這個問題涉及到測試模型誤差與摩卡:如何使用Mocha和rspec測試模型錯誤?

  1. 這是我的控制器(API /藝術家控制器):

    class Api::ArtistsController < ApplicationController 
        respond_to :json 
    
        def create 
        artist = Artist.new(params[:artist]) 
        if artist.save <-- This is where the test fails 
         render :json=>artist 
        else 
         respond_with artist 
        end 
        end 
    end 
    
  2. 這是我的模型(藝術家模型):

    class Artist < ActiveRecord::Base 
        include Core::BaseModel 
        attr_accessible :name 
        has_many :albums 
        validates :name, :presence=>true, :uniqueness=>{:case_sensitive=> false} 
        default_scope where :deleted=>false 
    end 
    
  3. 這是它發生故障時,有關藝術家控制器測試:

    it "should not save a duplicated artist" do 
        Artist.any_instance.stubs(:is_valid?).returns(false) 
        Artist.any_instance.stubs(:errors).returns({:name=>[I18n.t('activerecord.errors.messages.taken')]}) 
        post :create, :format => :json 
    
        expect(response).not_to be_success 
        expect(response.code).to eq("422") 
    
        results = JSON.parse(response.body) 
        expect(results).to include({ 
         "errors"=>{ 
         "name"=>[I18n.t('activerecord.errors.messages.taken')] 
         } 
        }) 
    end 
    

當我運行測試,這是我得到的上述測試錯誤:

Failure/Error: post :create, :format => :json 
    NoMethodError: 
     undefined method `add_on_blank' for {}:Hash 
    # ./app/controllers/api/artists_controller.rb:17:in `create' 
    # ./spec/controllers/api/artists_controller_spec.rb:56:in `block (3 levels) in <top (required)>' 

我開始使用摩卡,所以我不知道是否有一個當我想測試重複名稱的驗證時,測試特定情況下json結果的方法。

回答

0

ActiveRecord::Base#errors(即Artist#errors)不是簡單的散列。它應該是ActiveModel::Errors的一個實例。你用哈希對它進行了存根,並且ActiveRecord正試圖對其調用add_on_blank,這是失敗的。

我不認爲save調用is_valid?可言的,我懷疑它的運行驗證,然後試圖調用add_on_blank追加一個錯誤,但既然你已經掐滅errors,這是失敗的。

這不是測試控制器的好方法。它對Artist的內部做了太多的假設。你也在測試那些不屬於控制器的東西; errors未在操作的任何位置引用。唯一值得在控制器中測試的行爲是否會創建Artist;如果Artist無法保存,它會呈現JSON;如果保存成功,則重定向。這是控制者的全部責任。

如果要測試以某種方式呈現錯誤,則應該編寫單獨的視圖規範。如果你想測試缺少的字段會產生錯誤,你應該寫一個模型規範。如果您不想編寫視圖規範,依靠模型填充errors(在模型規範中測試),並且在您的控制器中,只需測試render的調用json設置爲Artist實例就足夠了。

一般來說最好儘可能避免殘留物,但在這種情況下,我認爲殘留的唯一的東西是Artist.new以返回模擬,並且save在該模擬上返回false。然後我會檢查一下,確保它是用模擬渲染的。

更簡單的選擇是創建一個實際的Artist記錄,然後用重複的參數調用post來觸發驗證失敗。缺點是你碰到了數據庫,而在控制器規範中避免這種情況值得讚賞,但通常更方便。如果你想在你的控制器規格中避免數據庫命中,你可以在Capybara功能規格中做到這一點。

如果你想嘗試測試你的方式,你可以手動創建的ActiveModel::Errors實例並填充的部分,或存根方法,並踩滅Artist.any_instance.stubs(:errors)ActiveModel::Errors兼容的行爲,回到你的嘲笑,但是這是一個很多嘲笑。

最後一個提示:不要使用post :create, :format => :json。使用xhr :post, :create生成真正的Ajax請求,而不是依賴於format參數。這是對路由和響應代碼的更強大的測試。

+0

如何「你不應該這樣做」回答這個問題? –