我正在编写一个程序,允许用户匹配最终在它们之间传输内容的事务中的订单。
我有一个类TransferAsset,它接受交易并为交易的购买者创建资产:
class TransferAsset
attr_accessor :transaction, :seed_asset
def initialize(opts = {})
@transaction = opts[:transaction]
end
def create_seed_asset
@seed_asset = UserInventoryFactory.new({transaction: transaction}).inventory
end
end
这是UserInventory类:
class UserInventoryFactory
attr_accessor :transaction, :inventory
def initialize(opts = {})
@transaction = opts[:transaction]
create_user_inventory
set_values
end
def set_values
set_seed_transaction
set_owner
set_amount
set_purchase_date
set_initial_amount
end
def create_user_inventory
@inventory = UserInventory.new
end
def set_seed_transaction
inventory.seed_transaction_id = transaction.id
end
def set_owner
inventory.user_id = transaction.buyer_id
end
def set_amount
inventory.amount = transaction.amount
end
def set_purchase_date
inventory.purchase_date = transaction.created_at.beginning_of_day
end
def set_initial_amount
inventory.initial_amount = transaction.amount
end
end
我对TransferAsset类进行了rspec测试:
describe '#create_seed_asset' do
it 'creates an asset for the purchaser' do
factory = UserInventoryFactory.new({transaction: transaction})
expect(transfer.create_seed_asset).to eql factory.inventory
end
end
测试失败了:
1) TransferAsset#create_seed_asset creates an asset for the purchaser
Failure/Error: expect(transfer.create_seed_asset).to eql factory.inventory
expected: #<UserInventory id: nil, amount: 5000.0, initial_amount: 5000.0, purchase_date: "2014-06-22 05:00:00", user_id: 2, seed_transaction_id: 1, created_at: nil, updated_at: nil>
got: #<UserInventory id: nil, amount: 5000.0, initial_amount: 5000.0, purchase_date: "2014-06-22 05:00:00", user_id: 2, seed_transaction_id: 1, created_at: nil, updated_at: nil>
(compared using eql?)
我已经尝试了所有的rspec相等匹配器,它总是失败,这让我觉得我在编写错误的代码时,无论是在我的测试中还是在我的实际类中。
我做错了什么或我能做得更好?
答案 0 :(得分:2)
您需要覆盖您的类的相等方法。现在它是默认比较对象ID,因为它们不是内存中的同一个对象,它总是错误的。
尝试覆盖==来比较两个对象的实例变量
==对于新类的默认行为,忽略继承,是比较对象ID
答案 1 :(得分:1)
您正在尝试比较UserInventory
类的两个不同实例,每个实例都使用create_user_inventory
方法创建:
def create_user_inventory @inventory = UserInventory.new end
比较两者会给你错误,如下所示:
Object.new.eql? Object.new
# => false
让两个具有相同类的对象(甚至是相同的属性值)不会使它们相等,并且您不能指望默认的比较方法知道它们是。
像字符串,数组和映射这样的对象有自己的带有自定义语义的比较器实现,如果你希望你的类有自己的语义 - 你还应该实现它们的自定义比较器,并定义那些语义。
另见here:
Ruby有三个主要的相等测试方法,
==
,eql?
和equal?
。这些 方法通常存在于Object类中,因为所有其他Ruby都存在 类继承自Object,它们自动获得对这些的访问权限 三种方法。在Object类中,所有方法都完全正确 同样的事情,他们测试两个对象是否完全相同的对象。 也就是说,两个对象必须具有相同的对象ID。
答案 2 :(得分:1)
由于您只想测试对象等效性,您可以将对象转换为JSON并比较结果。
它避免了重新定义平等方法。因此,您可以将测试更改为:
describe '#create_seed_asset' do
it 'creates an asset for the purchaser' do
factory = UserInventoryFactory.new({transaction: transaction})
expect(transfer.create_seed_asset.to_json).to eql factory.inventory.to_json
end
end