rspec测试中的未定义方法

use*_*194 1 ruby rspec ruby-on-rails

我在rspec中运行集成测试,测试不断抛出一个未定义的方法billed_for:

"undefined method billed_fornil:NilClass"

require 'user'

describe "Integration" do
  let(:user) { User.new(voucher) }

  context 'no voucher' do
    let(:voucher) { nil }

    it 'should bill default price all the time' do
      user.bill
      expect(user.orders[0].billed_for).to eql 6.95
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

到目前为止,我的用户类非常少

require 'order'
require 'voucher'

class User
  attr_accessor :voucher, :orders

  def initialize(orders = [], voucher = nil)
    @voucher = voucher
    @orders = [orders]
  end

  def bill
    new_order = Order.new(self)
    @orders << new_order
  end
end
Run Code Online (Sandbox Code Playgroud)

和一个同样小的订单类:

class Order
  DEFAULT_PRICE = 6.95

  attr_accessor :user

  def initialize(user)
    @user = user
  end

  def billed_for
    price = DEFAULT_PRICE
    user.orders.each do |order|
        price - order.billed_for
    end
    price
  end
end
Run Code Online (Sandbox Code Playgroud)

让我最困惑的是这条线

user.orders[0].billed_for
Run Code Online (Sandbox Code Playgroud)

当我想通过一个新的用户类设置这个让我,然后我访问用户哈希中的订单哈希,然后我正在访问billed_for订单类中的方法.

当我用谷歌搜索这个问题时,它指向使用不起作用的self关键字.

如果有人能指出我正确的方向,那就太好了

编辑:

雅各布S善意地指出我的测试失败了,因为我的数组中的nil条目.

快速修复此问题只是为了运行紧凑功能来删除nil条目.

当然,始终向更好的解决方案开放.

编辑2:

let(:user) { User.new(voucher) }

context 'no voucher' do
  let(:voucher) { nil }

  it 'should bill default price all the time' do
      user.bill
      expect(user.orders[0].billed_for).to eql 6.95
      ... ...
  end
end

context 'vouchers' do
  describe 'default vouchers' do
    let(:voucher) { Voucher.create(:default, credit: 15) }

    it 'should not bill user if has a remaining credit' do
      user.bill
      expect(user.orders[0].billed_for).to eql 0.0
      ... ...
    end
  end
Run Code Online (Sandbox Code Playgroud)

感谢你目前的帮助.我还开了一个额外的帖子,因为我有一些其他类似的问题

访问其他类的变量

Jak*_*b S 5

当您实例化您的时user,您可以使用

let(:user) { User.new(voucher) }
Run Code Online (Sandbox Code Playgroud)

voucher被定义为nil

let(:voucher) { nil }
Run Code Online (Sandbox Code Playgroud)

换句话说,您使用实例化user变量User.new(nil).

您的User构造函数具有签名

def initialize(orders = [], voucher = nil)
Run Code Online (Sandbox Code Playgroud)

所以通过User.new(nil)你将orders参数设置为nil(voucher也是nil,但默认情况下).然后你的构造函数继续创建一个实例变量,@orders它设置为[orders]- 在这种情况下是相同的[nil].

然后你的测试继续进行,并向@orders数组添加一个新订单,这很好,并且让你的@orders数组包含[nil, instance_of(Order)].

最后,测试尝试将billed_for方法发送到orders数组中的第一个元素:user.orders[0].billed_for.orders数组包含[nil, instance_of(Order)],第一个元素是nil,因此你实际上是在调用

nil.billed_for
Run Code Online (Sandbox Code Playgroud)

在您的规范中,这会导致您看到的错误.

我想你可能会有点接近你被没有通过寻找什么voucherorders实例化时的说法User.你的测试也可能想检查最后一个元素,user.orders.last而不是user.orders[0].我怀疑你可能会偶然发现一些改进.