ruby-on-rails-3 - 如何使用 Mocha 和 rspec 测试模型错误?

标签 ruby-on-rails-3 rspec mocha.js rails-models

我遇到了与使用 Mocha 测试模型错误相关的问题:

  1. 这是我的 Controller (Api/Artist Controller ):

    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. 这是关于 Artist Controller 的测试失败的地方:

    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)>'

我开始使用Mocha,所以当我想测试重复名称的验证时,我不知道是否有办法测试特定情况下的json结果。

最佳答案

ActiveRecord::Base#errors (即 Artist#errors )不是一个简单的哈希。它应该是 ActiveModel::Errors 的一个实例。您正在使用哈希对其进行 stub ,并且 ActiveRecord 正在尝试调用 add_on_blank就这样,失败了。

我不认为save调用is_valid?根本没有,我怀疑它正在运行验证,然后尝试调用 add_on_blank附加错误,但因为您已经删除了 errors ,这是失败的。

这并不是测试 Controller 的好方法。它对Artist的内部做出了太多假设。 。您还在测试根本不属于 Controller 的东西; errors未在操作中的任何地方引用。 Controller 中唯一值得测试的行为是它是否创建 Artist ;如果是Artist保存失败,它用它渲染 JSON;如果保存成功,它会重定向。这就是 Controller 的全部责任。

如果您想测试错误是否以某种方式呈现,您应该编写一个单独的 View 规范。如果您想测试缺失的字段是否会产生错误,您应该编写模型规范。如果您不想编写 View 规范,依靠模型来填充 errors 仍然足够。 (在模型规范中测试),并在您的 Controller 中,只需测试 render被调用 json设置为 Artist实例。

一般来说,最好尽可能避免 stub ,但在这种情况下,我唯一考虑 stub 的是 Artist.new返回模拟,并且 save在那个模拟上返回 false。然后我会检查以确保它是用模拟渲染的。

更简单的选择是创建一个实际的 Artist录音,然后调用post使用重复的参数来触发验证失败。缺点是您需要访问数据库,而在 Controller 规范中避免这样做是值得称赞的,但通常更方便。如果您想避免 Controller 规范中的数据库命中,您可以在 Capybara 功能规范中执行此操作。

如果您想尝试测试自己的方式,您可以手动创建 ActiveModel::Errors 的实例并填充它,或者对其进行 stub 方法,然后 stub Artist.any_instance.stubs(:errors)返回您的模拟 ActiveModel::Errors -兼容的行为,但这是很多 mock 。

最后一个提示:不要使用 post :create, :format => :json 。使用xhr :post, :create生成真正的 Ajax 请求,而不是依赖 format参数。这是对您的路由和响应代码的更可靠的测试。

关于ruby-on-rails-3 - 如何使用 Mocha 和 rspec 测试模型错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15696560/

相关文章:

ruby-on-rails - 有没有办法在 RSpec 中先运行嵌套的前置过滤器?

unit-testing - 编写单元测试以检查事件是否被触发

javascript - Mocha 不会失败测试

ruby-on-rails-3 - 导轨 : Content_for in partial

ruby-on-rails - 未定义的方法 `microposts'

ruby-on-rails - 如何将可选的 URL 参数映射到 params[ :something] in Rails 3 "routes.rb"?

ruby - 在 Rspec 测试中运行 Rake 任务

ruby - Buildr, RSpec——将构建参数传递给测试

javascript - 异步运行 mocha js (AND-like)

jquery - 使 AJAX 请求转到正确的 URL