Dazed RSpec

Sorry, but this is starting to feel like a kick to the head. RSpec. Watched video after video, read tutorial after tutorial and yet I just got stuck on the square.

=== this is what I am working with

http://github.com/fudgestudios/bort/tree/master

=== Errors

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

      

=== here is my controller action

  def bid

      @bid = Bid.new(params[:bid])
      @bid.save

  end

      

=== here is my 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/tree/master/spec/spec_helper.rb

It's a shame that you have to wake up to work at 3 am and do nothing during the day. Please understand.

0


source to share


4 answers


You have a couple of things back before (: each). As an example, it is indicated that the message should increase the score by 1, you are dealing with real records, and there is no reason to cut something down. Also, for now, since there is only one example, there is no reason to have before the block. I would do it like this:

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

      



One thing I would recommend is to create these things in VERY detail until you understand them better. Start by waiting (the message should change the number of bids), run the spec and let the failure message give you the option to add whatever you need in the spec or in code.

+18


source


Jesse,

This will continue if you comment out the 2nd two lines before (: each), which does not affect the "must create a new ticket" example.

The lambda keyword creates an arbitrary block of code that is not executed when it is defined, but is actually an object that you can assign to a variable and execute later:

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

      

At this point the code is not executed, but we can refer to it using the "the_post" variable. Now we can send it "should" and then "change ...", for example:

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

      



Several things happen when this line is executed. The stuff to the right of the "should" is first evaluated by initializing an rspec mate object with some instructions. This match is the "must" argument - the equivalent of this:

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

      

The 'should' method is called on the_post, which is a block of code (which hasn't been executed yet). Under the hood, the "must" method passes self (the_post) to the matches, so the helper now has everything it needs to evaluate the example.

The connector calls Bid.count and writes the value. It then executes the block (the_post) and then calls Bid.count a second time and compares it to the value it wrote earlier. In this case, since we want the Bid.count to change by 1 (positive here is implied - will increase by 1), if that happens, the matches are silent and the example passes.

If the values ​​are the same or differ by some value other than 1, the example will fail. You can see this work if you change the expectation to (2) rather than (1).

NTN, David

+3


source


EDIT: you shouldn't expect the Bid.count to increase when using the layout object. Mantra I forgot: caffeine before the code.

Just by commenting out the lines while the original is still there.

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

      

Try to write as little specifications as possible, write your settings in such a way that it is obvious what you should check in that specification. For example, how I changed your from it "should work"

to it "should create a new Bid"

. If there is more for that controller, write a new specification for each small piece of functionality.

If you end up in need of mock users, there are some restful_authentication helpers that make things easier. First create a custom fixture in RAILS_ROOT/spec/fixtures/users.yml

, for example:

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"

      

Then in your spec, you can write the following and have your method current_user

and all other restul_authentication parts behave as you would expect them at runtime.

login_as :quentin
# .... the rest of your spec

      

As an example of a few additional specifications, I could add a couple more examples:

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

      

+2


source


I don't quite understand what is going on yet. (with cigarette butts and lambda) ....

for

def bid
  @bid = Bid.new params[:bid]
  @bid.save
end

      

The next ones are coming through !!

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

      

0


source







All Articles