rspec 测试中的未定义方法 [英] Undefined Method in rspec testing

查看:44
本文介绍了rspec 测试中的未定义方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

"未定义的方法 billed_for nil:NilClass"

需要用户"描述整合"做let(:user) { User.new(凭证) }上下文无凭证"做让(:优惠券){零}它应该一直对默认价格收费"吗用户帐单期望(user.orders[0].billed_for).to eql 6.95结尾结尾结尾

到目前为止我有一个非常小的用户类

需要'订单'需要凭证"类用户attr_accessor :凭证,:订单def 初始化(订单 = [],凭证 = 零)@voucher = 代金券@orders = [订单]结尾定单new_order = Order.new(self)@订单<<新命令结尾结尾

还有一个同样小的订单类:

class 顺序DEFAULT_PRICE = 6.95attr_accessor : 用户定义初始化(用户)@用户 = 用户结尾def billed_for价格 = DEFAULT_PRICEuser.orders.each 做 |order|价格 - order.billed_for结尾价格结尾结尾

最让我困惑的是这条线

user.orders[0].billed_for

当我认为它通过一个新的用户类设置时,我然后访问用户哈希中的订单哈希,然后我访问订单类中的 billed_for 方法.

当我用谷歌搜索这个问题时,它指出使用了无效的 self 关键字.

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

Jakob S 善意地指出,由于数组中的条目为零,我的测试失败了.

对此的快速解决方法是运行紧凑函数以删除 nil 条目.

当然总是对更好的解决方案持开放态度.

编辑 2:

let(:user) { User.new(voucher) }上下文无凭证"做让(:优惠券){零}它应该一直对默认价格收费"吗用户帐单期望(user.orders[0].billed_for).to eql 6.95……结尾结尾上下文凭证"做描述默认凭证"做let(:voucher) { Voucher.create(:default, credit: 15) }'如果有剩余信用,它不应该向用户收费' 做用户帐单期望(user.orders[0].billed_for).to eql 0.0……结尾结尾

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

访问其他类的变量

解决方案

当你实例化你的 user 时,你使用

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

voucher

中定义为nil

let(:voucher) { nil }

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

您的 User 构造函数具有签名

def 初始化(订单 = [],凭证 = 零)

所以通过执行 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

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

我认为通过在实例化 Uservoucher 传递给 orders 参数,您可能会更接近您要查找的内容代码>.此外,您的测试可能想要检查最后一个元素,即 user.orders.last 而不是 user.orders[0].而且我怀疑您在进行过程中可能会发现更多改进.

I'm running an integration test in rspec and the test keeps throwing up an undefined method on billed_for:

"undefined method billed_for nil: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

I have a very small user class so far

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

and an equally small order class:

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

What's confusing me most is this line

user.orders[0].billed_for

when I think it through a new user class is set up this let, I then access the orders hash in user hash and then I'm accessing the billed_for method within the order class.

When I've googled this issue it's pointed towards using the self keyword that isn't working.

If someone could point me in the right direction it'd be great

EDIT:

Jakob S kindly pointed at that my test was failing because of nil entries in my array.

A quick an dirty fix for this was just to run the compact function to remove the nil entry.

Always open to better solutions of course.

EDIT 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

Thanks for the help so far. I've also opened an additional thread as I had a few other similar questions

Accessing variables of other classes

解决方案

When you instantiate your user, you use

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

voucher is defined as nil in

let(:voucher) { nil }

In other words you instantiate your user variable with User.new(nil).

Your User constructor has the signature

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

so by doing User.new(nil) you're setting the orders argument to nil (voucher is also nil, but that's by default). Your constructor then goes ahead and creates an instance variable, @orders that it sets to [orders] - which in this case is the same as [nil].

Your test then goes ahead and adds a new order to the @orders Array, which is fine, and that leaves your @orders array containing [nil, instance_of(Order)].

Finally, the test tries to send the billed_for method to the first elements in the orders array: user.orders[0].billed_for. The orders array contains [nil, instance_of(Order)], the first element of that is nil, thus you're actually calling

nil.billed_for

in your spec, which results in the error you're seeing.

I think you might get a bit closer to what you're looking for by not passing the voucher to the orders argument when instantiating the User. Also your test might want to check the last element, ie user.orders.last rather than user.orders[0]. And I suspect you might stumble across a few more improvements as you go along.

这篇关于rspec 测试中的未定义方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆