0

コントローラーをテストして、許可された関係者だけが RSpec を使用して正しい子オブジェクトを表示できることを確認しようとしています。このエラーが発生しているため、何が間違っているのかわかりません。

ActiveRecord::RecordInvalid: Validation failed: Company can't be blank

Plan オブジェクトと Company オブジェクトがあります。ストアには多くの計画があります (害虫駆除会社を考えてみてください)。既知のシナリオが与えられた場合、会社の計画を取得できることをテストしたいと思います (1 つしかないと仮定します)。

プランは次のようになります。

class Plan < ActiveRecord::Base
  before_save :default_values

  # Validation
  validates :amount, :presence => true
  validates :company, :presence => true

  # Plans belong to a particular company.
  belongs_to :company, :autosave => true    

  scope :find_all_plans_for_company, lambda {
    |company| where(:company_id => company.id)
  }
  # Other code ...

end 

会社は次のようになります。

class Company < ActiveRecord::Base
  validates :name, :presence => true
  validates :phone1, :presence => true

  validates_format_of :phone1, :phone2,
                      :with => /^[\(\)0-9\- \+\.]{10,20}$/,
                      :message => "Invalid phone number, must be 10 digits. e.g. - 415-555-1212",
                      :allow_blank => true,
                      :allow_nil => true

  has_many :users
  has_many :plans

end

..コントローラーはこんな感じ

def index
    @plans = Plan.find_all_plans_for_company(current_user.company)

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @plans }
    end
  end

.. そして、私の RSpec テストは次のようになります (ギミックがいっぱいで申し訳ありません。私はそれをいじっているだけで、動作させることができません)。

describe PlansController do

  def valid_attributes
    {
        :company_id => 1,
        :amount => 1000
    }
  end

  describe "GET index" do
    it "should return the Plans for which this users company has" do

      @company = mock_model(Company, :id => 1, :name => "Test Company", :phone1 => "555-121-1212")
      Company.stub(:find).with(@company.id).and_return(@company)

      controller.stub_chain(:current_user, :company).and_return(@company)

      plan = Plan.create! valid_attributes

      get :index, {}
      assigns(:plans).should eq([plan])
    end

    # Other tests ...
  end

end

問題は、これ(または私が試したクレイジーな他のバリアントのいずれか)を試すと、次のエラーが発生することです。

ActiveRecord::RecordInvalid: Validation failed: Company can't be blank

Company.stub呼び出しでこれが処理されると思っていたので、なぜこれが起こっているのかわかりません。しかし、どうやらそうではありません。

ここで何が欠けていて、何が間違っていますか? どうすればこのテストに合格できますか?

4

3 に答える 3

2

物事が理にかなっていることを確認するために (そして何が起こっているのかを確実に理解するために)、この仕様のレイヤーをはがしてみましょう。まず、何をテストしていますか?

it "should return the Plans for which this users company has" do

  ...

  assigns(:plans).should eq([plan])

したがって、現在のユーザーの会社に関連付けられているプラ​​ンが に割り当てられていることを確認します@plans。他のすべてをスタブまたはモックアウトできます。

コントローラーのコードを見ると、次のようになります。

def index
  @plans = Plan.find_all_plans_for_company(current_user.company)

データベースにアクセスせず、モデルに依存せずにこれを機能させるには何が必要ですか?

まず、 からモックを取得しcompanyますcurrent_user.company。これは、仕様コードの次の 2 行が行うことです。

  @company = mock_model(Company, :id => 1, :name => "Test Company", :phone1 => "555-121-1212")
  controller.stub_chain(:current_user, :company).and_return(@company)

これによりcurrent_user.company、モック モデルが返され@companyます。ここまでは順調ですね。

クラスメソッドに移りましょうfind_all_plans_for_company。これは私が少し混乱しているところです。仕様では、findメソッドをスタブしてforCompanyを返します。@companyid = 1

しかし、実際には、コントローラー コードで次のようなことを行うだけで十分ではないでしょうか?:

  @plans = current_user.company.plans

このようにすると、テストで計画をモックし、それをplansモック会社の関連付けとして返すことができます。

  @plan = mock_model(Plan)
  @company = mock_model(Company, :plans => [ @plan ])
  controller.stub_chain(:current_user, :company).and_return(@company)

その後、割り当てが機能するはずであり、実際にモデルを作成したり、データベースにアクセスしたりする必要はありません。モックの会社に id やその他の属性を与える必要さえありませんが、これらはとにかく仕様には関係ありません。

多分私はここで何かを見逃しています、もしそうなら私に知らせてください。

于 2012-08-04T05:31:26.927 に答える
1

なぜあなたはモックする必要がありますか?

私の標準的なテスト設定は、テスト中に作成されたレコードからデータベースをクリアするデータベースクリーナーを使用することです。このようにして、テストは実際のデータベースレコードを使用して実行され、その結果、各テストの後にテストデータベースから削除されます。

また、テスト中にモデルのインスタンスを作成するためのFactory Girlを確認することもできます(たとえば、10の会社レコードを簡単に作成できます)。

見る:

于 2012-08-04T06:11:37.180 に答える
0

あなたの問題を解決できる 3 つの考えがあります。

  1. attr_accessible :company_idPlan クラスに追加してみてください。

  2. company_id が 1 の Plan を作成すると、mock_model は実際にはデータベースに保存されないため、データベースに存在しないため検証に失敗します。

  3. Planbefore_save :default_valuesクラスで、新しく作成されたインスタンスの company_id 属性を台無しにしないようにします。

于 2012-08-03T23:22:51.017 に答える