rspec等于匹配失败,对象看似相同

时间:2014-06-22 19:02:45

标签: ruby-on-rails ruby rspec

我正在编写一个程序,允许用户匹配最终在它们之间传输内容的事务中的订单。

我有一个类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相等匹配器,它总是失败,这让我觉得我在编写错误的代码时,无论是在我的测试中还是在我的实际类中。

我做错了什么或我能做得更好?

3 个答案:

答案 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