Ruby on rails 被RSpec惊呆了

Ruby on rails 被RSpec惊呆了,ruby-on-rails,ruby,testing,rspec,Ruby On Rails,Ruby,Testing,Rspec,我很抱歉,但这开始让我觉得像是在踢自己的头。我完全被RSpec搞糊涂了。看了一段又一段的视频,读了一段又一段的教程,但我还是一头雾水 这就是我的工作内容 ==错误 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

我很抱歉,但这开始让我觉得像是在踢自己的头。我完全被RSpec搞糊涂了。看了一段又一段的视频,读了一段又一段的教程,但我还是一头雾水

这就是我的工作内容

==错误

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
==规范\u辅助程序


凌晨3点起床上班,一天一事无成,真令人沮丧。请理解。

编辑:使用模拟对象时,不应期望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“应该工作”
更改为
it“应该创建一个新的出价”
。如果有更多的控制器,写一个新的规范 对于每个小功能块

如果您最终需要模拟用户,那么有一些restful_身份验证的帮助工具可以使它变得更容易。首先在中创建一个用户装置
RAILS\u 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"
the_post.should change(Bid, :count).by(1)
作为更多规范的示例,我可能会添加更多示例:

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

虽然我不太明白发生了什么。(带短桩和lambda)

为了

以下通过

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

你以前有两件事是倒过来的。因为示例指定post应该将计数增加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
我推荐的一件事是,在你更好地理解它们之前,现在就要非常精细地创建这些东西。从期望开始(post应该更改出价计数),运行规范,让失败消息引导您在规范或代码中添加所需的任何内容。

Jesse

如果您注释掉before(:each)的后两行,它仍然会通过,这对“应该创建新出价”示例没有影响

lambda关键字创建的任意代码块在定义时不会执行,但实际上是可以分配给变量并在以后执行的对象:

the_post = lambda do
  post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end
此时代码不会执行,但我们可以使用'theu post'变量引用它。现在我们可以发送“应该”,然后是“更改…”,如下所示:

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"
the_post.should change(Bid, :count).by(1)
当执行这一行时,会发生一些事情。首先计算“应该”右侧的材质,使用一些指令初始化rspec匹配器对象。该匹配器是“应该”的参数,相当于:

matcher = change(Bid, :count).by(1)
the_post.should(matcher)
在_post上调用'should'方法,这是代码块(尚未执行)。在引擎盖下,“应该”方法将self(theu post)传递给匹配器,因此匹配器现在拥有评估示例所需的一切

匹配器调用Bid.count并记录值。然后执行块(_post),然后再次调用Bid.count并将其与之前记录的值进行比较。在本例中,由于我们希望Bid.count更改为1(此处隐式为正值-增加1),如果发生这种情况,匹配器将保持沉默,示例通过

如果这些值相同,或不同于1,则示例将失败。如果将期望值改为(2)而不是(1),则可以看到这一点

嗯,,
David

您能发布您的型号代码吗?我假设您已经检查过它是否派生自ActiveRecord::Base。