如何在 Rspec 中存根 Class 对象?
How do I stub a Class object in Rspec?
我正在努力执行封装(但可能做得不是很好),并想测试 Rspec 中的代码。客户 class 在工厂 class 中实例化时将采用 class 对象(作为 klass)。通过尚未存在的 UI,客户将创建一个订单。
我目前的测试如下。我只是想确认订单是Order class。
describe 'Customer' do
let(:customer){Customer.new}
let(:customer_with_instantiation){Customer.new(:klass=>order, :name=>'Oscar Wilde', :number=>'0234567')}
let(:order){double :order, :name=>:order}
it 'klass object to be the order class when customer is instantiated with a klass attribute' do
expect(customer_with_instantiation.klass).to be_a(order)
end
end
Class代码如下:
class Customer
attr_accessor :name, :number, :klass
DEFAULT_CUSTOMER_ORDER = {:order_detail => [{ :dish=>"",
:item_count=>0 }],
:order_total_cost=>0 }
def initialize(options={})
@name=options.fetch(:name, "")
@number=options.fetch(:number, "")
@klass=options.fetch(:klass, Object)
@customer_order=DEFAULT_CUSTOMER_ORDER
end
def place_order(menu)
#requires user input
customer_order=klass.new({:order_detail => [{:dish => :pizza, :item_count => 3},
{:dish => :burger, :item_count => 3}],
:order_total_cost => 210})
klass.test_customer_order(customer_order, self)
end
end
class Order
attr_reader :order_detail, :order_total_cost
attr_accessor :total_check
def initialize(options={})
@order_detail=options.fetch(:order_detail, Object)
@order_total_cost=options.fetch(:order_total_cost, Object)
end
def self.test_customer_order(customer_order, customer, menu, assistant)
customer_order.total_check = 0
customer_order.order_detail.each do |order_item|
menu.dishes.each do |dish|
if order_item[:dish]==dish.name
customer_order.total_check += dish.price*order_item[:item_count]
end
end
end
assistant.take_order(customer_order, customer, customer_order.total_check)
end
end
感谢任何帮助!
通过使用 be_a
,您正在测试 klass
是 klass
的一个实例,这可能不是您想要的。
在我看来,在测试 initialize
方法和 klass
的 getter 时(这实际上是您正在做的),您应该只感兴趣确认您发送到 Customer.new
的任何内容都可以在之后读取。
所以也许是这样的:
class Foo
attr_reader :klass
def initialize(args)
@klass = args.fetch(:klass)
end
end
describe Foo do
describe "#initialize" do
let(:klass) { double }
let(:instance) { Foo.new(klass: klass)}
it "sets klass" do
expect(instance.klass).to eq(klass)
end
end
end
一些一般要点:
- 如果您想测试订单是否是
klass
的实例,您可能应该重写代码以使其更易于测试
在这种情况下,klass
不是一个非常有用的名称。目前尚不清楚为什么 Customer
需要一个类。
- 您想将订单与客户解耦,但客户显然对订单的接口做了一些假设。你真的有所成就吗?
- 我建议不要将测试方法放在 classes 中,而是放在测试文件中。
- 在
fetch
中使用 Object
作为默认值可能不是您想要的。首先,您可能希望它们是某些 class,而不是 class 对象的实例。
- 创建订单真的是
Customer
class实例的工作吗?如果重点是确保可以根据用户输入实例化任何类型的抽象订单,也许单独的 OrderCreator
class 会更合适?此 class 可以接受用户数据和订单 class 以及受影响的客户。
我正在努力执行封装(但可能做得不是很好),并想测试 Rspec 中的代码。客户 class 在工厂 class 中实例化时将采用 class 对象(作为 klass)。通过尚未存在的 UI,客户将创建一个订单。
我目前的测试如下。我只是想确认订单是Order class。
describe 'Customer' do
let(:customer){Customer.new}
let(:customer_with_instantiation){Customer.new(:klass=>order, :name=>'Oscar Wilde', :number=>'0234567')}
let(:order){double :order, :name=>:order}
it 'klass object to be the order class when customer is instantiated with a klass attribute' do
expect(customer_with_instantiation.klass).to be_a(order)
end
end
Class代码如下:
class Customer
attr_accessor :name, :number, :klass
DEFAULT_CUSTOMER_ORDER = {:order_detail => [{ :dish=>"",
:item_count=>0 }],
:order_total_cost=>0 }
def initialize(options={})
@name=options.fetch(:name, "")
@number=options.fetch(:number, "")
@klass=options.fetch(:klass, Object)
@customer_order=DEFAULT_CUSTOMER_ORDER
end
def place_order(menu)
#requires user input
customer_order=klass.new({:order_detail => [{:dish => :pizza, :item_count => 3},
{:dish => :burger, :item_count => 3}],
:order_total_cost => 210})
klass.test_customer_order(customer_order, self)
end
end
class Order
attr_reader :order_detail, :order_total_cost
attr_accessor :total_check
def initialize(options={})
@order_detail=options.fetch(:order_detail, Object)
@order_total_cost=options.fetch(:order_total_cost, Object)
end
def self.test_customer_order(customer_order, customer, menu, assistant)
customer_order.total_check = 0
customer_order.order_detail.each do |order_item|
menu.dishes.each do |dish|
if order_item[:dish]==dish.name
customer_order.total_check += dish.price*order_item[:item_count]
end
end
end
assistant.take_order(customer_order, customer, customer_order.total_check)
end
end
感谢任何帮助!
通过使用 be_a
,您正在测试 klass
是 klass
的一个实例,这可能不是您想要的。
在我看来,在测试 initialize
方法和 klass
的 getter 时(这实际上是您正在做的),您应该只感兴趣确认您发送到 Customer.new
的任何内容都可以在之后读取。
所以也许是这样的:
class Foo
attr_reader :klass
def initialize(args)
@klass = args.fetch(:klass)
end
end
describe Foo do
describe "#initialize" do
let(:klass) { double }
let(:instance) { Foo.new(klass: klass)}
it "sets klass" do
expect(instance.klass).to eq(klass)
end
end
end
一些一般要点:
- 如果您想测试订单是否是
klass
的实例,您可能应该重写代码以使其更易于测试
在这种情况下, klass
不是一个非常有用的名称。目前尚不清楚为什么Customer
需要一个类。- 您想将订单与客户解耦,但客户显然对订单的接口做了一些假设。你真的有所成就吗?
- 我建议不要将测试方法放在 classes 中,而是放在测试文件中。
- 在
fetch
中使用Object
作为默认值可能不是您想要的。首先,您可能希望它们是某些 class,而不是 class 对象的实例。 - 创建订单真的是
Customer
class实例的工作吗?如果重点是确保可以根据用户输入实例化任何类型的抽象订单,也许单独的OrderCreator
class 会更合适?此 class 可以接受用户数据和订单 class 以及受影响的客户。