2

いくつかの RSpec コントローラー テストがあります。うまくいくものもあれば、うまくいかないものもあり、私は地球上でそれらを修正してより効率的にする方法を見つけようとしています

理想的には、各仕様を次の形式にできるかどうかを確認したいと思います

subject { ... }
  it { ... }
  it { ... }
  it { ... }

すべてのコントローラー仕様について、実際のコントローラー アクション用のマクロを作成したことに注意してください。マクロはすべてテスト済みで、すべて動作します。名前から、その機能がかなり明確になります。

私の「作成」テスト:

formats ||= ["html", "js"]
formats.each do |format|
  context "valid attributes" do
    subject { do_post_create( :customer, valid_attributes, format ) }
      its(:response_code) { should eq(302)}
      it { should redirect_to admin_customer_path(Customer.find_by_id(???))}
      it { expect { subject }.to change(Customer, :count).by(1) }
  end

  context "invalid attributes" do
    subject { do_post_create( :customer, invalid_attributes, format ) }
      its(:response_code) { should eq(200)}
      it { should render_template :new }
      it { expect { subject }.to_not change(Customer, :count).by(1) }
  end
end

その仕様では、post ステートメントから新しく作成されたオブジェクトの ID を取得する方法を見つけようとしています。「Customer.last」を試してみましたが、うまくいかないようです。何かご意見は?

私の「更新」仕様:

formats ||= ["html", "js"]
formats.each do |format|
  context "valid attributes" do
    let(:object) { FactoryGirl.create(:customer) }
    subject { do_put_update( class_to_symbol(model), object.id, attributes, format ) }
      its(:response_code) { should eq(302)}

    it "does alter #{model}" do
      do_put_update( class_to_symbol(model), object.id, attributes, format )
      assigns(:customer).should eq(object)
      flash[:notice].should =~ /Success/
      object.reload
      attributes.each do |key, value|
        object.send(key.to_s).should eq(value)
      end
    end
  end
  context "invalid attributes" do
    let(:object) { FactoryGirl.create("customer") }
    let(:invalid_attributes) { {:username => "!"} }
    subject { do_put_update( class_to_symbol(model), object.id, invalid_attributes, format ) }
      its(:response_code) { should eq(200)}

    it "does not alter #{model}" do
      do_put_update( class_to_symbol(model), object.id, invalid_attributes, format )
      assigns(:customer).should eq(object)
      flash[:notice].should =~ /Fail/
      object.reload
      attributes.each do |key, value|
        object.send(key.to_s).should_not eq(value)
      end
    end
  end
end

Update テストでは、2 番目のブロックをより簡潔な方法で、理想的にはすべてのテストで同じ「対象」ステートメントを使用できる方法で表現したいと思います。それは可能ですか?

4

1 に答える 1

3

この仕様を考えすぎていると思います。subjectすべての仕様を事前定義された形式 ( / /...)に強制しようとする代わりに、it何が起こるべきかを明確に文書化するように仕様を記述し、後でコードをリファクタリングしてみてください

適切な例: 暗黙的subjectな for コントローラー アクションの使用。subjectメソッドでitsはなくオブジェクトで使用することを意図しており、そのように使用した場合にのみ意味があります。たとえば、これは理にかなっています。

subject { [1, 2, 3, 4] }
its(:size) { should == 4 }

ここでは、何がテストされているかが完全に明確です。4 要素の配列のサイズは 4 です。

ただし、次のように記述します。

subject { do_post_create( :customer, valid_attributes, format ) }
its(:response_code) { should eq(302)}

アクションを検査しないと、その応答コードをどこから取得しているのかは明確ではありませんdo_post_createあなたは、マクロの名前が「何をするかをかなり明白にする」と言いますが、マクロが何を返すかをかなり明白にしていません。これは暗黙の主語を使用するための鍵です。主語になるのは戻り値だからです。 .

次のように書くだけで、より明確になります。

it "responds with a 302" do
  do_post_create(:customer, valid_attributes, format)
  response.should eq(302)
end

また、暗黙のサブジェクトを含む仕様と含まない仕様を混在させることはお勧めしません。実際にテストしているものをさらに混乱させるからです。contextたとえば、無効な属性ブロックでは件名を設定しますが、2 番目の仕様ではcustomer( assigns(:customer).should eq(object)) の割り当てを実際にテストするため、基本的に件名はこのテストには関係ありません。(しかし、ここでサブジェクトを設定してからそれを使用しないと、実際には PUT リクエストを( 経由で) 2 回送信することになります。これは、問題を引き起こす可能性があります。これもまた、ブロックdo_put_update内でリクエストを作成しない別の理由です。)subject

私は続けることができますが、あなたは写真を手に入れると思います。読みやすさを損なわずに仕様を短く簡潔にすることは素晴らしいことですが、この場合はやり過ぎだと思います。

ほんの 2 セントです。お役に立てば幸いです。

ps 上記の見解が少し極端に思える場合は、暗黙的サブジェクトのドキュメントを読んでください。ここでは、公開テストで暗黙的サブジェクトをまったく使用しないことを実際に推奨していることがわかります。

以下の例は、サブジェクトがユーザー向けの概念としてどのように使用されるかを示していますが、例からサブジェクトの使用を隠すカスタムマッチャーや拡張ライブラリのサポートのために予約することをお勧めします。

于 2012-10-29T12:27:14.117 に答える