2

Mocha を使用したモデル エラーのテストに関連するこの問題があります。

  1. これは私のコントローラーです(Api / Artistコントローラー):

    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 コントローラーに関する失敗したテストです。

    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結果をテストする方法があるかどうかわかりません。

4

1 に答える 1

2

ActiveRecord::Base#errors(つまりArtist#errors) 単純なハッシュではありません。のインスタンスであるはずですActiveModel::Errors。ハッシュでスタブしており、ActiveRecord がそれを呼び出そうとしてadd_on_blankいますが、失敗しています。

save呼び出しはまったくないと思います。検証を実行してから呼び出してエラーを追加is_valid?しようとしていると思われますが、スタブアウトしたため、失敗しています。add_on_blankerrors

これは、コントローラーをテストするための良い方法ではありません。の内部構造について仮定が多すぎArtistます。また、コントローラーの一部ではないものもテストしています。errorsアクションのどこにも参照されていません。Artistコントローラーでテストする価値のある唯一の動作は、それが;を作成するかどうかです。Artist保存に失敗した場合は、JSON をレンダリングします。保存が成功すると、リダイレクトされます。それがすべてのコントローラーの責任です。

エラーが特定の方法でレンダリングされることをテストしたい場合は、別のビュー仕様を作成する必要があります。欠落しているフィールドがエラーを生成することをテストする場合は、モデル仕様を作成する必要があります。ビュー スペックを記述したくない場合でも、モデルにデータを入力するerrors(モデル スペックでテストする) ことに依存するだけで十分です。コントローラーでは、インスタンスに設定してrender呼び出されたものをテストするだけです。jsonArtist

一般的に言えば、可能な限りスタブ化を避けるのが最善ですが、この場合、スタブ化を検討する唯一のことは、モックを返しArtist.newsaveそのモックで false を返すことです。次に、モックでレンダリングされていることを確認します。

より簡単なオプションは、実際のArtistレコードを作成してから、重複したパラメーターで呼び出しpostて検証の失敗をトリガーすることです。マイナス面は、データベースにヒットすることです。コントローラーの仕様でそれを回避することは称賛に値しますが、一般的にはより便利です。コントローラー仕様で DB ヒットを回避したい場合は、代わりに Capybara 機能仕様でそれを行うことができます。

自分のやり方でテストしたい場合は、のインスタンスを手動で作成してそれを設定ActiveModel::Errorsするか、メソッドをスタブして、スタブアウトして、互換性のある動作でArtist.any_instance.stubs(:errors)モックを返すことができますが、それは多くのモックです。ActiveModel::Errors

最後のヒント: を使用しないでくださいpost :create, :format => :json。パラメータxhr :post, :createに依存するのではなく、実際の Ajax リクエストを生成するために使用します。formatこれは、ルーティングと応答コードのより堅牢なテストです。

于 2013-03-29T03:38:34.777 に答える