Почему «каждый» метод итератора ломает rspec? - PullRequest
1 голос
/ 10 октября 2011

Фон

Я пытаюсь протестировать свои модели.

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 /action.rb

class Transaction < ActiveRecord::Base

  attr_accessor :user

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

end

В классе транзакций @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

Использование rspec2.6.4, factory_girl 2.1.2, рельсы 3.1.0, ruby ​​1.9.2p290.Как показано, спецификация проходит.

Задача

Когда я изменяю метод transactions в 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.each {|transaction| transaction.user = self}
    transactions
  end

end

метод transactions теперь возвращает [] в rspec, , однако он отлично работает в представлениях приложения .

, поскольку Transaction.userэфемерный (представляющий пользователя, обращающегося к транзакции), он должен быть установлен (если он существует) каждый раз, когда транзакция инициализируется или строится из записей в БД.

Я в растерянности, с чего начатьотладить это.

Все предложения приветствуются!

Ответы [ 3 ]

3 голосов
/ 10 октября 2011

Я думаю, что ваша проблема заключается в том, что let ленив.В основном происходит то, что транзакции еще даже не создаются, когда в тесте вызывается метод transactions.Используйте let! для не ленивой версии.Подробнее см. let and let! .

1 голос
/ 10 октября 2011

Не могли бы вы просто вернуть payor_transactions + payee_transactions вместо их ручного выбора?

0 голосов
/ 11 октября 2011

Следуя предложению @obrok, решение, на котором я остановился, чтобы сохранить преимущество ленивой загрузки let в других тестах, заключалось в том, чтобы касаться каждой транзакции перед проверкой транзакций пользователя # следующим образом:

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
...