rspec 测试中的未定义方法 [英] Undefined Method in rspec testing
问题描述
我正在 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
在您的规范中,这会导致您看到的错误.
我认为通过在实例化 User时不将
代码>.此外,您的测试可能想要检查最后一个元素,即 voucher
传递给 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屋!