1

私はrspecチュートリアル(peepcodeチュートリアル)を実行しています。私はいくつかの足場を生成しました、そして誰かが説明を書き直して初心者のためにもう少し明確に読むことができる方法を説明するのを手伝ってくれることを望んでいました。

describe "POST create" do

    describe "with valid params" do
      it "assigns a newly created weather as @weather" do
        Weather.stub(:new).with({'these' => 'params'}) { mock_weather(:save => true) }
        post :create, :weather => {'these' => 'params'}
        assigns(:weather).should be(mock_weather)
      end

end

このコード行は私が理解しようとしているものですこれはこれです

Weather.stub(:new).with({'these' => 'params'}) { mock_weather(:save => true) }

中括弧の中にメソッドが入れられているのを見たことがありません。これは実際にはどういう意味ですか?

{ mock_weather(:save => true) }
4

2 に答える 2

6

その声明は次のことを意味します。

パラメータを使用newしてクラスのメソッドをスタブし、式の値を返しますWeather'these'=>'params'mock_weather(:save => true)

これを書くための同様の、おそらくより明確な方法は次のようになります。

Weather.stub(:new).with({'these'=>'params'}).and_return(mock_weather(:save => true))

構文{< some code>は、スタブが呼び出されたときに実行されるコード ブロック}を作成します。

.and_return()2 つの形式との戻り値{}はわずかに異なります。最初のケースではスタブが定義されたときに決定され、2 番目のケースではメッセージが受信されたときに決定されます。それらは一般に互換性がありますが、そうでない場合もあります。

編集

この回答はモックについて誤解を招くものであり、回答に値すると思います。

「もう少しわかりやすくする方法」に関する最初の質問については、モックを使用しないことから始めることができます。モック オブジェクトは、セカンダリ オブジェクト (重要ではないがテスト ケースに存在する必要があるオブジェクト) の予測可能な動作に依存できない場合に役立ちます。モック オブジェクトの使用の典型的な例は、データベース クエリ、ネットワークの使用、ファイル I/O です。コンピューターがネットワーク接続を失った、またはデータベースが利用できないためにテストが失敗するのは望ましくありません。

確かに、モックは外部リソースへの依存を排除​​できますが、それが唯一の目的ではありません。モックの本当の価値は、まだ存在しないコードのテストを作成できることです。たとえば Rails では、最初にビュー仕様を書くことから始めることにするかもしれません。

describe "posts/show.html.erb" do
  it "displays the author name" do
    assign(:post,mock('post',:author=>"Mark Twain"))
    render
    rendered.should contain("written by Mark Twain")
  end
end

この仕様では、データベース、コントローラー、またはモデルの存在は必要ありません。ビューが文字列をレンダリングする必要があることをアサートし、それがレンダリングされることを確認するだけです。Rails ビューが関係するのはこれだけです。唯一の依存関係は、テンプレート ファイルと、ステートメント@postによって処理されるインスタンス変数の存在です。に応答するだけで、何がassign何であるかは気にしません。@post:author

rails g scaffold から取得した生成コードは最適ではありません。生成されたコードは、すべてのテストに合格するように生成されており、そのためにモック オブジェクトを使用しています。なぜ彼らがそうするのかわからないが、より良いデフォルトはテストを失敗させることだと思うので、実際にテストを成功させるために何かをする必要がある.

scaffold の全体的なアイデアは、通常のユース ケースで機能するコードを生成することで時間を節約することです。生成されたテストも実際に機能することを望みませんか?

もちろん、スキャフォールディングを使用することで、BDD/TDD の「テスト ファースト」パラダイムを回避することになりますが、おそらく関連するトレードオフを受け入れているか、そもそもスキャフォールディングを使用していないでしょう。

「モックオブジェクトを使用する理由」に関しては、コントローラーの仕様をモデルとデータベースから切り離すことができます。そうです、その理由がわかれば、それは「最適」です。

自動生成されたモック ファイルを使用すると、何もする必要がなく、テストは永久にパスし続けます。それは悪い考えであり、悪い習慣です。

サブジェクトコードを壊さない限り、それらは合格します。そのため、回帰テストにおいて価値があり、コードが仕様を満たさなくなるような方法で新しいコードやリファクタリングを導入していないことを確認できます。

モデル ファイルに検証ルールを記述する必要があり、モック オブジェクトを使用していないため、実際の検証が行われていることを確認できます。

この種の結合は、Rails コントローラーの仕様では実際には望ましくありません。コントローラーは、モデルについて可能な限り知識を持たないようにする必要があるため、コントローラーの仕様では、検証が成功 (または失敗) したときに何が起こるかを定義するだけで済みます。足場によって提供されるモックは、まさにそれを行います。モデル インスタンスが特定のパラメータ セットに対して有効かどうかをテストする必要がある場合は、モデル スペックでそれを行います。

于 2011-02-04T17:20:34.053 に答える
1

「少しわかりやすくする方法」に関する最初の質問については、モックを使用しないことから始めることができます。

モック オブジェクトは、セカンダリ オブジェクト (重要ではないがテスト ケースに存在する必要があるオブジェクト) の予測可能な動作に依存できない場合に役立ちます。モック オブジェクトの使用の典型的な例は、データベース クエリ、ネットワークの使用、ファイル I/O です。コンピューターがネットワーク接続を失った、またはデータベースが利用できないためにテストが失敗するのは望ましくありません。

から取得した生成コードrails g scaffoldは最適ではありません。生成されたコードは、すべてのテストに合格するように生成されており、そのためにモック オブジェクトを使用しています。なぜ彼らがそうするのかわからないが、より良いデフォルトはテストに失敗することだと思うので、実際にテストを成功させるために何かをする必要がある.

生成されたモックを削除して、次のようにします。

#spec/controllers/weather_controller_spec.rb
describe "POST create" do
  describe "with valid params" do
    it "assigns a newly created weather as @weather" do
      post :create, :weather => {'location' => 'ORD', 'temp'=>'35', 'sample_time'=>'2011-02-04T20:00-0500'}
      assigns(:weather).should be_valid
    end

    it "should redirect you to the weather show page" do
      post :create, :weather => {'location' => 'ORD', 'temp'=>'35', 'sample_time'=>'2011-02-04T20:00-0500'}
      response.should redirect_to(weather_path(assigns[:weather]))
    end
  end

  describe "without valid params" do
    it "should notify that a location is required" do
      post :create, :weather => {'temp'=>'35', 'sample_time'=>'2011-02-04T20:00-0500'}
      flash[:notice].should == 'Location is required.'
      assigns(:weather).should_not be_valid
    end

    it "should notify that a temperature is required" do
      post :create, :weather => {'location' => 'ORD', 'sample_time'=>'2011-02-04T20:00-0500'}
      flash[:notice].should == 'A temperature is required.'
      assigns(:weather).should_not be_valid
    end

    it "should notify that a sample time is required" do
      post :create, :weather => {'location' => 'ORD', 'temp'=>'35'}
      flash[:notice].should == 'A sample time is required.'
      assigns(:weather).should_not be_valid
    end
  end
end

モック オブジェクトを使用していないことに注意してください。そのため、コードは、いくつかのパラメーターを指定して POST 呼び出しを行い、オブジェクトが有効であることを確認するだけです。モデル ファイルに検証ルールを記述する必要があり、モック オブジェクトを使用していないため、実際の検証が行われていることを確認できます。

自動生成されたモック ファイルを使用すると、何もする必要がなく、テストは永久にパスし続けます。それは悪い考えであり、悪い習慣です。

また、無効なパラメーターや欠落しているパラメーターがある場合を実行するテストをさらに作成する必要があることにも注意してください。繰り返しassigns(:weather).should_not be_validますが、実行することで、検証が機能していることを確認しています。

呼び出すたびにパラメーターの辞書を作成するのpost :createは、反復的で、壊れやすく、見苦しいものです。フィクスチャの使い方を勉強する必要があります。たとえばファクトリーガールの場合

#spec/factories.rb
Factory.define :weather_valid do |f|
  f.location "ORD"
  f.temp "35"
  f.sample_time "2011-02-04T20:00-0500"
end


#spec/controllers/weather_controller_spec.rb
describe "POST create" do
  describe "with valid params" do
    it "assigns a newly created weather as @weather" do
      post :create, :weather => Factory.build(:weather_valid).attributes
      assigns(:weather).should be_valid
    end

    it "should redirect you to the weather show page" do
      post :create, :weather => Factory.build(:weather_valid).attributes
      response.should redirect_to(weather_path(assigns[:weather]))
    end
  end
...

これにより、再利用可能で読みやすいコードが得られます。

于 2011-02-04T18:05:08.987 に答える