16

MichaelHartlによるRubyOnRailsチュートリアルを行っている間、作成者がサインアップページを検証するための統合テストを作成するセクションで、彼は次のコードスピネットを使用しました。コードの機能はわかりましたが、「どのように」の部分に頭を悩ませることができませんでした。つまり、実行の順序を理解できませんでした。

expect { click_button "Create my account" }.not_to change(User, :count)

誰かが上記のメソッドとブロックのチェーンのセマンティクスとそれらがどのように組み合わされるかを説明できますか?

4

2 に答える 2

45

expect ... change特定のメソッド呼び出しが他の値を変更する (または変更しない) ことを確認するために使用します。この場合:

expect { click_button "Create my account" }.not_to change(User, :count)

rspec に次のことをさせる:

  1. 実行User.countして、返された値をメモします。(これは、例のようにレシーバーとメソッド名(User, :count)として、または{ User.count }.
  2. Runclick_button "Create my account"は、リンク上でのマウス クリックをシミュレートする Capybara メソッドです。
  3. もう一度実行User.countします。
  4. #1 と #3 の結果を比較します。それらが異なる場合、この例は失敗します。同じなら合格です。

その他の使用方法expect ... change:

expect { thing.destroy }.to change(Thing, :count).from(1).to(0)
expect { thing.tax = 5 }.to change { thing.total_price }.by(5)
expect { thing.save! }.to raise_error
expect { thing.symbolize_name }.to change { thing.name }.from(String).to(Symbol)

一部のドキュメントはこちらにあります。

これがどのように行われるかは少し難解であり、それを使用するためにどのように機能するかを理解する必要はまったくありません。への呼び出しexpectは、rspec 独自のカスタム DSL と「マッチャー」のシステムを使用して、rspec が実行する構造を定義しています。Gary Bernhardt はかなりきちんとしたスクリーンキャストを持っており、rspec の謎は実際には ruby​​ のような動的言語から自然に抜け落ちていると主張しています。rspec の使い方の入門としては適切ではありませんが、rspec がどのように機能するのかに興味がある場合は、興味深いと思うかもしれません。

アップデート

別の回答に関するコメントを確認した後、操作の順序について少し追加します。直観的でないトリックは、すべてのブロックを実行するのはマッチャー(この場合) だということです。ラムダを持ち、その仕事がラムダをマッチャーに渡すエイリアスです。この場合のマッチャーは、自身の引数を 1 回実行してから、渡されたラムダ ( からのもの) を実行し、独自の引数を再度実行して、状況が変化したかどうかを確認することを認識しています。行が左から右に実行されるように見えるので注意が必要ですが、ほとんどの部分はコードのブロックを通過しているだけなので、マッチャーにとって最も意味のある順序にシャッフルすることができます。changeexpectnot_toshould_notchangeexpect

私は rspec 内部の専門家ではありませんが、基本的な考え方については理解しています。

于 2012-05-18T01:55:41.060 に答える
4

以下は、Request Specs と Capybara に関する Ryan Bates Railscastからの抜粋です。

require 'spec_helper'  

describe "Tasks" do  
  describe "GET /tasks" do  
    it "displays tasks" do  
      Task.create!(:name => "paint fence")  
      visit tasks_path  
      page.should have_content("paint fence")  
    end  
  end  

  describe "POST /tasks" do  
    it "creates a task" do  
      visit tasks_path  
      fill_in "Name", :with => "mow lawn"  
      click_button "Add"  
      page.should have_content("Successfully added task.")  
      page.should have_content("mow lawn")  
    end  
  end  
end  

そして、これは RSPec Expectations に関するドキュメントからの抜粋です

describe Counter, "#increment" do
  it "should increment the count" do
    expect{Counter.increment}.to change{Counter.count}.from(0).to(1)
  end

  # deliberate failure
  it "should increment the count by 2" do
    expect{Counter.increment}.to change{Counter.count}.by(2)
  end
end

したがって、基本的には、

expect { click_button "Create my account" }.not_to change(User, :count)

RSpec の一部:

expect {...}.not_to change(User, :count)

そしてカピバラの一部

click_button "Create my account"

(ここに Capyabara DSL へのリンクがあります -- 検索できますclick_button)

両方の全体的な例を探しているようです。これは完璧な例ではありませんが、次のようになります。

describe "Tasks" do  
  describe "GET /tasks" do  
    it "displays tasks" do  
      expect { click_button "Create my account" }.not_to change(User, :count)
    end  
  end 
end 
于 2012-05-18T01:37:14.540 に答える