为什么“每个”是“每个”?迭代器方法中断 rspec?

发布于 2024-12-08 16:53:14 字数 2458 浏览 0 评论 0原文

背景

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

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

the method transactions now在 rspec 中返回 []但它在应用程序视图中完美运行

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

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

感谢所有建议!

Background

I'm attempting to test my models.

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

In the Transactions class, @user is an ephemeral object instance representing the user accessing the model.

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

Using rspec 2.6.4, factory_girl 2.1.2, rails 3.1.0, ruby 1.9.2p290. As shown, the spec passes.

Problem

When I modify the transactions method in app/models/user.rb to iterate over the results such that it reads:

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

the method transactions now returns [] in rspec, however it works perfectly in the app views.

Since Transaction.user is ephemeral (representing the user accessing the transaction) it must be set (if it exists) every time a Transaction is initialized or built from db records.

I'm at a loss for where to begin to debug this.

All suggestions appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

面如桃花 2024-12-15 16:53:14

我认为你的问题在于 let 是懒惰的。基本上发生的情况是,当在测试中调用 transactions 方法时,事务甚至还没有创建。使用 let! 作为非惰性版本。有关更多信息,请参阅 let 和 let!细节。

I think your problem lies in the fact that let is lazy. Basically what is happening is that the transactions are not even created yet when the transactions method is called in the test. Use let! for a non-lazy version. See let and let! for more details.

三生路 2024-12-15 16:53:14

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

Couldn't you just return payor_transactions + payee_transactions instead of manually selecting them?

深巷少女 2024-12-15 16:53:14

根据 @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

Following the suggestion from @obrok, the solution I settled on to retain the advantage of lazy-loading let in other tests was to touch each transaction before testing User#transactions as so:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文