【问题标题】:Why does the "each" iterator method break rspec?为什么“每个”迭代器方法会破坏 rspec?
【发布时间】:2011-10-09 20:29:14
【问题描述】:

背景

我正在尝试测试我的模型。

app/models/user.rb

class User < ActiveRecord::Base

  has_many :payor_transactions, class_name: 'Transaction', inverse_of: :payor, foreign_key: :payor_id
  has_many :payee_transactions, class_name: 'Transaction', inverse_of: :payee, foreign_key: :payee_id

  def transactions
    transactions = Transaction.where(["payor_id=? OR payee_id=?", self.id, self.id])
    transactions
  end

end

app/models/transaction.rb

class Transaction < ActiveRecord::Base

  attr_accessor :user

  belongs_to :payor, class_name: 'User'
  belongs_to :payee, class_name: 'User'

end

在 Transactions 类中,@user 是一个临时对象实例,表示访问模型的用户。

spec/models/user_spec.rb

require 'spec_helper'

describe User do

  let(:user) { Factory(:user) }
  let(:user2) { Factory(:user) }
  let(:user3) { Factory(:user) }

  let(:transaction_user_user2) { Factory(:transaction, payor: user, payee: user2) }
  let(:transaction_user2_user) { Factory(:transaction, payor: user2, payee: user) }
  let(:transaction_user2_user3) { Factory(:transaction, payor: user2, payee: user3) }

  describe ".transactions" do
    it "should include payor and payee transactions but not 3rd party transactions" do
      user.transactions.should == [transaction_user_user2, transaction_user2_user]
      user2.transactions.should == [transaction_user_user2, transaction_user2_user, transaction_user2_user3]
      user3.transactions.should == [transaction_user2_user3]
    end
  end

end

使用 rspec 2.6.4、factory_girl 2.1.2、rails 3.1.0、ruby 1.9.2p290。如图所示,规范通过了。

问题

当我修改 app/models/user.rb 中的 transactions 方法以迭代结果时,结果如下:

class User < ActiveRecord::Base

  has_many :payor_transactions, class_name: 'Transaction', inverse_of: :payor, foreign_key: :payor_id
  has_many :payee_transactions, class_name: 'Transaction', inverse_of: :payee, foreign_key: :payee_id

  def transactions
    transactions = Transaction.where(["payor_id=? OR payee_id=?", self.id, self.id])
    transactions.each {|transaction| transaction.user = self}
    transactions
  end

end

transactions 方法现在在 rspec 中返回 []但是它在应用视图中完美运行

由于 Transaction.user 是临时的(代表访问事务的用户),因此必须在每次初始化事务或从数据库记录构建事务时设置(如果存在)。

我不知道从哪里开始调试。

感谢所有建议!

【问题讨论】:

  • 我还在学习 rspec,所以我认为这是我的 rspec 配置中的错误,而不是 rspec 本身的错误。
  • 我的 spec_helper.rb,以防万一:gist.github.com/1274147

标签: ruby-on-rails-3 unit-testing rspec2 ruby-1.9.2


【解决方案1】:

我认为你的问题在于let 是懒惰的。基本上发生的事情是在测试中调用transactions 方法时甚至还没有创建事务。将let! 用于非惰性版本。详情请见let and let!

【讨论】:

    【解决方案2】:

    您不能只返回 payor_transactions + payee_transactions 而不是手动选择它们吗?

    【讨论】:

    • 我打算添加分页,所以我需要在数据库级别进行联合,但transactions = self.payor_transactions + self.payee_transactions 会起作用。
    • 很公平。分页总是让事情变得更加困难。
    【解决方案3】:

    根据@obrok 的建议,我决定在其他测试中保留延迟加载let 的优势的解决方案是在测试 User#transactions 之前先触摸每个事务:

    describe ".transactions" do
      it "should include payor and payee transactions but not 3rd party transactions" do
    
        [transaction_user_user2, transaction_user2_user, transaction_user2_user3].each do |transaction|
          [transaction.payor_id, transaction.payee_id].each {|id| id.should_not be_nil }
        end
    
        user.transactions.should == [transaction_user_user2, transaction_user2_user]
        user2.transactions.should == [transaction_user_user2, transaction_user2_user, transaction_user2_user3]
        user3.transactions.should == [transaction_user2_user3]
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-27
      • 2021-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-08
      • 1970-01-01
      相关资源
      最近更新 更多