2013-03-29 41 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

如何“你不应该这样做”回答这个问题? –