【问题标题】:Rspec, Rails - unable to account for controller variable in testingRspec,Rails - 无法在测试中考虑控制器变量
【发布时间】:2014-07-07 21:51:14
【问题描述】:

我是测试新手。在我的 rspec 测试中,我似乎无法解释控制器中的变量。如何在我的测试中考虑所需的变量并使这些测试通过?

当前测试:

describe "POST create action" do
    let(:trip)              { create(:trip)}
    let(:trip_date)         { create(:trip_date) }
    let(:buyer)             { create(:buyer) }
    let(:company)           { create(:company) }
    let(:order_item)        { attributes_for(:order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }
    let(:bad_order_item)    { attributes_for(:bad_order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }

    context "given valid order item attributes" do
        it "creates a new order item" do
            expect{ post :create, order_item: order_item, trip_id: trip.id }.to change(OrderItem, :count).by(1)
        end
    end
end

这是我的错误信息:

OrderItemsController POST create with valid attributes creates a new order item
Failure/Error: expect{ post :create, order_item: FactoryGirl.attributes_for(:order_item) }.to change(OrderItem,:count).by(1)
NoMethodError:
       undefined method `company_id' for nil:NilClass
 # ./app/controllers/order_items_controller.rb:29:in `create'
 # ./spec/controllers/order_items_controller_spec.rb:47:in `block (4 levels) in <top (required)>'

错误引用了我的 order_items_controller.rb 的第 29 行:

line 25:    def create
line 26:        @trip = Trip.friendly.find_by_id(params[:trip_id)
line 27:        @order_item = OrderItem.new(order_item_params)
line 28:        @order_item.buyer_id            = current_user.id
line 29:        @order_item.company_id          = @trip.company_id
line 30:        @order_item.first_person_cost   = @trip.first_person_cost
line 31:        @order_item.second_person_cost  = @trip.second_person_cost

line 32:        if @order_item.save
line 33:            redirect_to cart_path(current_user), notice: 'New order item created.'
line 34:        else
line 35:            render 'new', notice: 'Unable to create new order item.'
line 36:        end    
line 37:    end  

影响此控制器操作的唯一回调是在操作开始之前确认用户已登录。如果不是,他们将被重定向到登录页面。

我也试过: 让(:旅行){创建(:旅行)} 让(:trip_date){创建(:trip_date)} 让(:买家){创建(:买家)} 让(:公司){创建(:公司)} 让(:order_item){attributes_for(:order_item,trip_date_id:trip_date.id,buyer_id:buyer.id,company_id:company.id)} 让(:bad_order_item){ attributes_for(:bad_order_item,trip_date_id:trip_date.id,buyer_id:buyer.id,company_id:company.id)}

describe "POST create" do
    let(:trip)     {create(:trip) }
    context "with valid attributes" do
        it "creates a new order item" do
          Trip.stub_chain(:friendly, :find_by_id).and_return(trip)
          expect{ post :create, order_item: order_item }.to change(OrderItem,:count).by(1)
          end
      end
    end
end

导致错误:

1) OrderItemsController POST create action given valid order item attributes creates a new order item
    Failure/Error: let(:trip)               { create(:trip)}
    Double received unexpected message :where with (no args)
        # ./spec/controllers/order_items_controller_spec.rb:34:in `block (3 levels) in <top (required)>'

此外,很难找到有关特定 Rpsec 代码的文档。我特别感谢为 rspec 的 'post' 方法指明正确的方向。

提前致谢。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 rspec factory-bot


    【解决方案1】:

    您不能在规范中分配一些变量并在控制器中获取它们!

    有几种方法可以测试它

    1 控制器在 DB 中找到记录 - 所以创建它以 Trip.friendly.find_by_id(params[:trip_id) 返回它

    describe "POST create" do
      let(:trip) { FactoryGirl.create(:trip) }
    
      context "with valid attributes" do
        it "creates a new order item" do
          order_item = FactoryGirl.attributes_for(:order_item)
          expect{ post :create, order_item: order_item, trip_id: trip.id }.to change(OrderItem,:count).by(1)
        end
      end
    end 
    

    2 使用stub(或stub_chain

    describe "POST create" do
      let(:trip) { FactoryGirl.create(:trip) }
      context "with valid attributes" do
        it "creates a new order item" do
          Trip.stub_chain(:friendly, :find_by_id).and_return(trip)
          order_item = FactoryGirl.attributes_for(:order_item)
          expect{ post :create, order_item: order_item }.to change(OrderItem,:count).by(1)
        end
      end
    end
    

    PS 至于我第一个变种更好,因为控制器真的接受params[:trip_id] 所以最好通过它。

    【讨论】:

    • 这些方法都再次开始失败。相同的错误信息。当我尝试您建议的第二个示例时,它返回“双重收到意外消息:where with (no args)”。没有其他测试开始失败,只有这个。
    • 您应该选择一种测试策略:存根一些查询或创建真实数据(我更喜欢为控制器测试创建真实数据)。根据您使用的错误double 接收“意外”方法where。在您发布的代码中,我在控制器中没有看到where,在测试中没有看到double。发布您的控制器和规范代码。
    • 我已经更新了最初工作的代码,但现在失败了。
    • 我不明白发生了什么:您创建了一个新的question(没关系),其中发布了相同的代码,但错误是undefined method company_id' for nil:NilClass`。在这里你说问题是“”双重收到意外消息:哪里“。而且你没有发布所有你得到错误的操作代码。请澄清所有这些事情
    • 我收到了两条错误消息。我已更新此问题以阐明哪种尝试会导致哪种错误消息,并删除了我的新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多