0

コントローラー テストでモデルの特定の属性をスタブ化するのが非常に難しいと感じています。スタブをできるだけ少なくしたいのです。


編集:私は、そのような統合にスタブを使用することをやめました。スタブがアクション コールに到達しないことがわかりました。正しい質問は次のようになります。

モックとスタブを使用して、Rails コントローラー テストで特定の状態をシミュレートするにはどうすればよいですか?


だから私は次のようなものに達しました:

仕様

require 'spec_helper'

describe TeamsController do
  let(:team) { FactoryGirl.create :team }

  context "having questions" do
    let(:competition) { FactoryGirl.create :competition }

    it "allows a team to enter a competition" do
      post(:enter_competition, id: team.id, competition_id: competition.id)

      assigns(:enroll).team.should == team
      assigns(:enroll).competition.should == competition
    end
  end

  # ...
end

工場

FactoryGirl.define do
  factory :team do
    name "Ruby team"
  end

  factory :competition, class: Competition do
    name "Competition with questions"

    after_create do |competition|
      competition.
        stub(:questions).
        and_return([ 
          "something"
        ])
    end
  end

  factory :empty_competition, class: Competition do
    name "Competition without questions"
    questions []

    after_create do |competition|
      competition.stub(:questions).and_return []
    end
  end
end

生産コード

class TeamsController < ApplicationController
  def enter_competition
    @team = Team.find params[:id]
    @competition = Competition.find params[:competition_id]
    @enroll = @team.enter_competition @competition

    render :nothing => true
  end
end

class Team < ActiveRecord::Base
  def enter_competition competition
    raise Competition::Closed if competition.questions.empty?

    enroll = Enroll.new team: self, competition: competition
    enroll.save
    enroll
  end
end

テストを実行すると、questions属性が存在するnilため、モデルでのチェック時にテストが失敗しますnil.empty?

そのメッセージの状態が正しく使用されるように、スタブが使用されないのはなぜですか? 私@competition.questionsはそうなると思っ[ "question" ]ていましたが、代わりにnil.

4

2 に答える 2

3

あなたが遭遇している問題stubは、Rubyオブジェクトのインスタンスで機能することです。同じ行を表すすべてのActiveRecordオブジェクトに影響するわけではありません。

postテストを修正する最も簡単な方法は、 :の前にこれをテストに追加することです。

Competition.stub(:find).and_return(competition)

必要な理由は、同じデータベース行を表している場合でも、スタブアウトされていないCompetition.find新しいオブジェクトを返すためです。スタブも同様に、の同じインスタンスを返すことを意味します。つまり、コントローラーはスタブされたを認識します。CompetitionquestionsfindCompetitionquestions

questionsただし、ファクトリを使用する開発者として何がスタブされているかが明確ではなく、実際のメソッドをテストできないことを意味するため、ファクトリにそのスタブを含めることはお勧めしません。Competition単体テストだけでなく、統合テストでも実行したい。

簡単に言うと、モデルのインスタンスでメソッドをスタブアウトする場合は、findそのモデル(またはモデルを見つけるために使用しているクラスメソッド)もスタブアウトする必要がありますが、そのようなスタブを使用することはお勧めできません。工場定義で。

于 2012-05-14T13:36:40.407 に答える
1

FactoryGirlを呼び出すとcreate、データベースレコードが作成され、コントローラーコードで取得します。したがって、取得するインスタンス(@team@competition)は純粋なActiveRecordであり、メソッドがスタブアウトされていません。

個人的に私はあなたにこのようなテストを書きます(データベースにはまったく触れません):

let(:team) { mock_model(Team) }
let(:competition) { mock_model(Competition) }

before do
  Team.stub(:find) { team }
  Competition.stub(:find) { competition }
end

次に、テストで次のようにします。

it "should call enter_competition on @team with @competition" do
  team.should_receive(:enter_competition).with(competition)

  post :enter_competition, id: 7, competition_id: 10

私はあなたのコントローラーが何をすることになっているのか、それについてあなたが何をテストしているのか本当にわかりません、ごめんなさい:(

于 2012-05-12T07:49:21.833 に答える