Stupefied di RSpec
-
03-07-2019 - |
Domanda
Mi dispiace, ma questo inizia a sentirmi a calci in testa. Sono completamente sconcertato da RSpec. Ho visto video dopo video, letto tutorial dopo tutorial, e sono ancora bloccato sul punto di partenza.
=== ecco cosa sto lavorando
http://github.com/fudgestudios/bort/tree/master
=== Errori
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
=== ecco l'azione del mio controller
def bid
@bid = Bid.new(params[:bid])
@bid.save
end
=== ecco il mio test
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 / albero / master / spec / spec_helper.rb
È molto scoraggiante svegliarsi per il lavoro alle 3 del mattino e non fare nulla per il giorno. Per favore, capisci.
Soluzione
Hai un paio di cose al contrario prima (: ognuna). Visto che l'esempio sta specificando che il post dovrebbe aumentare il conteggio di 1, hai a che fare con record reali e non c'è motivo di stubbare nulla. Inoltre, a questo punto, poiché esiste un solo esempio, non vi è alcun motivo per avere un blocco prima. Lo farei così:
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
Una cosa che consiglierei è creare queste cose MOLTO granularmente per ora fino a quando non le capirai meglio. Inizia con le aspettative (il post dovrebbe cambiare il conteggio delle offerte), esegui la specifica e lascia che il messaggio di errore ti guidi nell'aggiungere qualsiasi altra cosa di cui hai bisogno nella specifica o nel codice.
Altri suggerimenti
Jesse,
Passerà comunque se commenterai le 2 ° due righe di prima (: ognuna), che non hanno alcun impatto sulla "quot", dovrebbe creare una nuova offerta " esempio.
La parola chiave lambda crea un blocco arbitrario di codice che non viene eseguito quando lo si definisce, ma in realtà è un oggetto che è possibile assegnare a una variabile ed eseguire in seguito:
the_post = lambda do
post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end
A questo punto quel codice non viene eseguito, ma possiamo fare riferimento ad esso con la variabile 'the_post'. Ora possiamo inviarlo "should", seguito da "change ...", in questo modo:
the_post.should change(Bid, :count).by(1)
Quando viene eseguita questa riga, accadono alcune cose. Il materiale a destra di "should" viene valutato per primo, inizializzando un oggetto matcher rspec con alcune istruzioni. Quel matcher è l'argomento di "dovrebbe" - l'equivalente di questo:
matcher = change(Bid, :count).by(1)
the_post.should(matcher)
Il metodo 'should' è chiamato su the_post, che è il blocco di codice (che non è stato ancora eseguito). Sotto il cofano, il metodo 'should' passa self (the_post) al matcher, quindi il matcher ora ha tutto il necessario per valutare l'esempio.
Il matcher chiama Bid.count e registra il valore. Quindi esegue il blocco (the_post), quindi chiama Bid.count una seconda volta e lo confronta con il valore registrato in precedenza. In questo caso, poiché stiamo cercando Bid.count per cambiare di 1 (il positivo è implicito qui - aumenta di 1), se è quello che succede il matcher rimane in silenzio e l'esempio passa.
Se i valori sono uguali o differiscono di un valore diverso da 1, l'esempio fallirà. Puoi vedere che funziona se cambi l'aspettativa in da (2) anziché da (1).
HTH, David
EDIT: non dovresti aspettarti che Bid.count aumenti quando usi un oggetto simulato. Ho dimenticato il mantra: caffeina prima del codice.
Per ora basta commentare le righe, quindi l'originale è ancora lì.
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
Prova a scrivere le specifiche più piccole possibili, scrivi le tue impostazioni in modo da rendere ovvio ciò che dovresti verificare in quella specifica. Ad esempio, il modo in cui ho cambiato il tuo da esso " dovrebbe funzionare "
a esso " dovrebbe creare una nuova offerta "
. Se c'è di più in quel controller, scrivi una nuova specifica
per ogni piccola funzionalità.
Se finisci per aver bisogno di utenti finti, ci sono alcuni aiutanti per l'autenticazione restful che lo rendono più facile. Per prima cosa crea un dispositivo utente in
RAILS_ROOT / spec / fixtures / users.yml
, in questo modo:
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"
Quindi nelle tue specifiche sarai in grado di scrivere quanto segue e avere il tuo metodo current_user
e tutte le altre parti di restul_authentication
comportarsi come ci si aspetterebbe da loro in fase di esecuzione.
login_as :quentin
# .... the rest of your spec
Come esempio di alcune altre specifiche, potrei aggiungere altri due esempi:
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
Anche se non capisco bene cosa stia succedendo. (con mozziconi e lambda) ....
per
def bid
@bid = Bid.new params[:bid]
@bid.save
end
I seguenti passi !!
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