質問
申し訳ありませんが、これは頭の中で自分を蹴りたくなり始めています。私はRSpecに完全に困惑しています。次から次へとビデオを見て、チュートリアルごとにチュートリアルを読んで、それでも私は四角に止まっています。
===これが私が取り組んでいるものです
http://github.com/fudgestudios/bort/tree/master
===エラー
F
1)
NoMethodError in 'bidding on an item should work'
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.new_record?
spec/controllers/auction_controller_spec.rb:16:
spec/controllers/auction_controller_spec.rb:6:
Finished in 0.067139 seconds
1 example, 1 failure
===ここに私のコントローラーアクションがあります
def bid
@bid = Bid.new(params[:bid])
@bid.save
end
===ここに私のテストがあります
require File.dirname(__FILE__) + '/../spec_helper'
include ApplicationHelper
include UsersHelper
include AuthenticatedTestHelper
describe "bidding on an item" do
controller_name :items
before(:each) do
@user = mock_user
stub!(:current_user).and_return(@user)
end
it "should work" do
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
assigns[:bid].should be_new_record
end
end
=== spec_helper
http://github.com/fudgestudios/ bort / tree / master / spec / spec_helper.rb
午前3時に仕事のために目を覚まし、その日に何も達成しないのは非常に残念です。理解してください。
解決
before(:each)には後方にいくつかのものがあります。例として見ると、投稿でカウントを1増やす必要があると指定しているため、実際のレコードを処理しているため、スタブ化する理由はまったくありません。また、この時点では、例は1つしかないため、beforeブロックを作成する理由はありません。このようにします:
describe ItemsController, "bidding on an item" do
fixtures :users
it "should create a new Bid" do
login_as :quentin
lambda do
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end.should change(Bid, :count).by(1)
end
end
私がお勧めすることの1つは、これらをよりよく理解するまで、今のところ非常に細かく作成することです。期待から始めて(投稿は入札カウントを変更する必要があります)、仕様を実行し、失敗メッセージにガイドまたは仕様またはコードに必要なものを追加してもらいます。
他のヒント
ジェシー、
before(:each)の2番目の2行をコメントアウトした場合でも、「新しい入札を作成する必要があります」に影響はありません。例。
lambdaキーワードは、定義時に実行されないが、実際には変数に割り当てて後で実行できるオブジェクトである任意のコードブロックを作成します。
the_post = lambda do
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end
この時点では、コードは実行されませんが、「the_post」変数で参照できます。次のように、「should」に続いて「change ...」を送信できます。
the_post.should change(Bid, :count).by(1)
この行が実行されると、いくつかのことが起こります。 'should'の右側のマテリアルが最初に評価され、いくつかの指示でrspecマッチャーオブジェクトが初期化されます。そのマッチャーは 'should'の引数です-これと同等:
matcher = change(Bid, :count).by(1)
the_post.should(matcher)
「should」メソッドは、コードブロック(まだ実行されていない)であるthe_postで呼び出されます。内部では、 'should'メソッドはself(the_post)をマッチャーに渡します。そのため、マッチャーは例の評価に必要なものをすべて備えています。
マッチャーはBid.countを呼び出し、値を記録します。次に、ブロック(the_post)を実行し、Bid.countを2回呼び出して、以前に記録した値と比較します。この場合、Bid.countが1だけ変化することを探しているため(ここでは正の値が暗黙的-1ずつ増加します)、それが起こると、マッチャーはサイレントのままで、例はパスします。
値が同じ場合、または1以外の値が異なる場合、この例は失敗します。期待をby(1)ではなくby(2)に変更すると、その動作を確認できます。
HTH、 デビッド
編集:モックオブジェクトを使用するときにBid.countが増加することを期待しないでください。私が忘れていたマントラ:コードの前にカフェイン。
今は行をコメントアウトするだけなので、オリジナルはまだそこにあります。
require File.dirname(__FILE__) + '/../spec_helper'
include ApplicationHelper
include UsersHelper
include AuthenticatedTestHelper
describe "POST to bid_controller" do
controller_name :items
before(:each) do
#@bid = mock_model(Bid) # create a new mock model so we can verify the appropriate things
#Bid.stub!(:new).and_return(@bid) # stub the new class method on Bid to return our mock rather than a new ActiveRecord object.
# this separates our controller spec entirely from the database.
end
it "should create a new Bid" do
lambda do
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end.should change(Bid, :count).by(1)
end
# ... more specs
end
可能な限り小さな仕様を記述し、その仕様で検証すべき内容が明確になるように設定を記述してください。たとえば、 it" should work"
から it" should a new Bid"
に変更した場合。そのコントローラーにもっとあるなら、新しい仕様を書く
機能の小さな部分ごとに。
最終的に模擬ユーザーが必要になった場合、restful_authenticationのヘルパーを使用して簡単に実行できます。最初にユーザーフィクスチャを作成します
RAILS_ROOT / spec / fixtures / users.yml
、このように:
quentin:
login: quentin
email: quentin@example.com
salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
created_at: <%= 5.days.ago.to_s :db %>
activation_code: 8f24789ae988411ccf33ab0c30fe9106fab32e9b
activated_at: <%= 5.days.ago.to_s :db %>
name: "Quentin"
次に、仕様で次を記述し、 current_user
メソッドとrestul_authenticationの他のすべての部分を使用できます。
実行時に期待どおりに動作します。
login_as :quentin
# .... the rest of your spec
さらにいくつかの仕様の例として、さらに2つの例として追加します。
def do_post
# extracting the method under test, so I don't repeat myself
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end
it "should create a new Bid" do
lambda do
do_post
end.should change(Bid, :count).by(1)
end
it "should assign the Bid to the proper auction" do
@bid.should_receive(:auction_id=).with(1) # test this, I believe doing Bid.new(params[:bid]) sets the id directly not sets the model
do_post
end
it "should assign the Bid the proper points" do
@bid.should_receive(:point=).with(1)
do_post
end
何が起こっているのかよくわかりませんが。 (スタブとラムダを使用)....
for
def bid
@bid = Bid.new params[:bid]
@bid.save
end
次の合格!!
require File.dirname(__FILE__) + '/../spec_helper'
include ApplicationHelper
include UsersHelper
include AuthenticatedTestHelper
describe "bidding on an item" do
controller_name :items
fixtures :users
before(:each) do
@user = login_as :quentin
@bid = mock_model(Bid) # create a new mock model so we can verify the appropriate things
@bid.stub!(:new).and_return(@bid) # stub the new class method on Bid to return our mock rather than a new ActiveRecord object.
#Bid.stub!(:save).and_return(true)# this separates our controller spec entirely from the database.
end
it "should create a new Bid" do
lambda do
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end.should change(Bid, :count).by(1)
end
end