Ошеломленный RSpec - PullRequest
       7

Ошеломленный RSpec

0 голосов
/ 01 января 2009

Извините, но мне начинает бить себя по голове. Я полностью сбит с толку 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 часа ночи и ничего не делать в течение дня. Пожалуйста, поймите.

Ответы [ 4 ]

18 голосов
/ 01 января 2009

У вас есть пара вещей задом наперед (: каждый). В качестве примера указано, что сообщение должно увеличить количество на 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

Одна вещь, которую я бы порекомендовал, это создавать эти вещи ОЧЕНЬ детально, пока вы не поймете их лучше. Начните с ожидания (пост должен изменить количество ставок), запустите спецификацию и позвольте сообщению об ошибке подсказать вам, что нужно добавить в спецификацию или в код.

3 голосов
/ 14 февраля 2009

Джесси

Это все равно пройдет, если вы закомментируете 2-ые две строки ранее (: каждая), которые не влияют на пример «следует создать новую ставку».

Ключевое слово lambda создает произвольный блок кода, который не выполняется при его определении, но фактически является объектом, который можно назначить переменной и выполнить позже:

the_post = lambda do
  post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end

На данный момент этот код не выполняется, но мы можем ссылаться на него с помощью переменной 'the_post'. Теперь мы можем отправить его «следует», а затем «изменить ...», например:

the_post.should change(Bid, :count).by(1)

Когда эта строка выполняется, происходит несколько вещей. Материал справа от 'should' оценивается первым, инициализируя объект соответствия rspec с некоторыми инструкциями. Это совпадение является аргументом «следует» - эквивалент этого:

matcher = change(Bid, :count).by(1)
the_post.should(matcher)

Метод 'should' вызывается для the_post, который является блоком кода (который еще не был выполнен). Под капотом метод 'should' передает self (the_post) в matcher, поэтому matcher теперь имеет все необходимое для оценки примера.

Устройство сопоставления вызывает Bid.count и записывает значение. Затем он выполняет блок (the_post), а затем вызывает Bid.count во второй раз и сравнивает его со значением, записанным ранее. В этом случае, так как мы ищем, как Bid.count изменится на 1 (положительное здесь неявно - увеличено на 1), если это то, что происходит, средство сравнения молчит и пример пропускается.

Если значения одинаковы или отличаются на какое-либо значение, отличное от 1, пример завершится ошибкой. Вы можете увидеть эту работу, если вы измените ожидание на (2) вместо (1).

НТН, David

2 голосов
/ 01 января 2009

EDIT: вы не должны ожидать увеличения 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 create 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

В качестве примера еще нескольких спецификаций я могу добавить еще пару примеров:

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
0 голосов
/ 01 января 2009

Пока я не совсем понимаю, что происходит. (с заглушками и лямбдами) ....

для

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...