我遇到了困惑,将测试结合在一起并将其删除。我的问题是 - 在confirm_purchase_order
中测试create_order
和class PurchaseOrder
方法的最合适方法是什么?
我在代码中包含了相关代码:
class PurchaseOrder
attr_reader :customer, :products
def initialize(customer)
@products = {}
@customer = customer
end
....some other methods
def add_product(product, quantity = 1)
@products[product] = (@products[product] ? @products[product] + quantity : quantity )
puts "You haved added #{quantity} #{product.title}'s to your purchase order"
end
def confirm_purchase_order
purchase_order_total
raise "Your PO appears to be empty! Add some products and try again." unless self.total.to_f.round(2) > 0
create_order
create_invoice
return "We have generated an Invoice and created an order."
end
def create_order
order = Order.new(customer)
order.products = @products.clone
end
def create_invoice
invoice = Invoice.new(customer)
invoice.products = @products.clone
end
end
class Order
attr_reader :customer
attr_accessor :status, :total, :products
def initialize(customer)
@products = {}
@status = :pending
@customer = customer
end
class Customer
attr_reader :name, :type
def initialize(name, type)
@name = name.to_s
@type = type.to_sym
end
class Invoice
attr_reader :customer, :products
attr_accessor :total
def initialize(customer, products)
@products = {}
@customer = customer
@payment_recieved = false
end
end
我想测试confirm_purchase_order
方法以及create_order
中的class PurchaseOrder
方法。到目前为止我的方法:
我需要一些对象双打和实际的PurchaseOrder object
describe PurchaseOrder do
let(:product) { double :product, title: "guitar", price: 5 }
let(:order) { instance_double(Order) }
let(:customer) { double :customer, name: "Bob", type: :company }
let(:products) { {:product => 1} }
let(:purchase_order) { PurchaseOrder.new(customer) }
describe "#create_order" do
it "returns an order" do
expect(Order).to receive(:new).with(customer).and_return(order)
allow(order).to receive(products).and_return(???products??!)
purchase_order.add_product(product, 1)
purchase_order.create_order
expect(order.products).to eq (products)
end
end
end
我还看了一下使用:
# order.stub(:products).and_return(products_hash)
# allow_any_instance_of(Order).to receive(:products) { products_hash }
# order.should_receive(:products).and_return(products_hash)
设置订单double以在调用order.products
时返回产品哈希值,但这些都感觉他们过多地“操纵”测试。在confirm_purchase_order
中测试create_order
和class PurchaseOrder
方法的最合适方法是什么?
答案 0 :(得分:1)
在我看来,也许你给了PurchaseOrder
过多的责任。它现在对Order
和Invoice
有深入的了解。
我可能会测试当前的实现:
it "returns an order with the same products" do
expect_any_instance_of(Order).to receive(:products=).with(products: 1)
purchase_order.add_product(product, 1)
expect(purchase_order.create_order).to be_a(Order)
end
但也许有必要将PurchaseOrder
与Order
和Invoice
分开,并做一些这样的事情:
class Invoice
def self.from_purchase_order(purchase_order)
new(purchase_order.customer, purchase_order.products.clone)
end
end
class Order
def self.from_purchase_order(purchase_order)
new.tap(purchase_order.customer) do |invoice|
invoice.products = purchase_order.products.clone
end
end
end
class PurchaseOrder
# ...
def create_order
Order.from_purchase_order(self)
end
def create_invoice
Invoice.from_purchase_order(self)
end
end
describe PurchaseOrder do
let(:customer) { double('a customer')}
let(:purchase_order) { PurchaseOrder.new(customer) }
describe "#create_order" do
expect(Order).to receive(:from_purchase_order).with(purchase_order)
purchase_order.create_order
end
describe "#create_invoice" do
expect(Order).to receive(:from_purchase_order).with(purchase_order)
purchase_order.create_order
end
end
describe Order do
describe '.from_purchase_order' do
# test this
end
end
describe Order do
describe '.from_purchase_order' do
# test this
end
end
这样,您就可以让Order
和Invoice
类知道如何从PurchaseOrder
构建自己。您可以单独测试这些类方法。 create_order
和create_invoice
的测试变得更加简单。
我想到的其他一些事情:
对于products
,请尝试使用带有默认过程的哈希:
@products = Hash.new { |hash, unknown_key| hash[unknown_key] = 0 }
这样,您可以随时安全地执行@products[product] += 1
。