2013-07-01 4 views
5

Я создал объект службы, называемый транзакцией, который обрабатывает сделанный заказ, устанавливает платежи и затем устанавливает ассоциацию модели.Тестирование и издевательства с Rspec

Класс называется транзакцией двумя способами: initialize и pay. Я тестирую его в spec/services/ (он находится в app/services).

Метод initialize принимает account и некоторые параметры, переданные пользователем для обработки заказа.

Я пытаюсь проверить pay с rspec. Как я действительно делаю такой тест? Эта функция много продолжается. Например, он создает новые модели, а затем устанавливает некоторые ассоциации между ними.

До сих пор я создал двойной account следующим образом:

@account = double("account", :confirmed => true, :confirmed? => true)

Однако, есть много функций (и ассоциации), используемых в способе транзакции оплаты. Так, например, когда эти ассоциации называются (как только я называю Transaction.pay в тесте), он возвращает ошибку:

ActiveRecord::AssociationTypeMismatch: 
Business(#70250016824700) expected, got RSpec::Mocks:. 

business модель двойной так же, как account, и добавляется в качестве атрибута @account. Как я могу проверить свой Transaction.pay, когда он создает новые модели и ассоциации там?

Нужно ли издеваться над ними, как показано выше? Или есть лучший способ сделать это?

Я использую FactoryGirl, но я не могу использовать его, поскольку моя модель account использует Devise. Разработчики тестовых помощников не могут использоваться вне контроллеров, и поскольку я тестирую службы, это не сработает.

+0

FactoryGirl и Devise не должны быть проблемой. сервисные тесты должны быть похожи на тесты модели. вы должны иметь возможность использовать FactoryGirl для своих моделей, не так ли? – phoet

ответ

7

Трудно быть конкретным, так как вы не ваш класс Код транзакции, но на высоком уровне, вот что я бы рекомендовал:

  • Не используйте FactoryGirl или Придумайте помощников - в идеале, вы пишете модульный тест для этого класса, поэтому вам не нужны внешние зависимости.
  • Вырезать любые экземпляры модели, с которыми вы имеете дело - это то, что вы сделали с account.
  • Вырезать любые внешние классы, используемые в службе (например, Business), и если вы создаете экземпляры тех, что есть в классах, то они тоже удваиваются.

Вот расплывчатый пример без реального осуществления:

require './app/services/transaction' 

describe Transaction do 
    let(:transaction) { Transaction.new account, :foo => 'bar' } 
    let(:account)  { double 'Account', :confirmed? => true } 
    let(:business) { double 'Business', :save => true } 

    before :each do 
    stub_const 'Business', double(:new => business) 
    end 

    describe '#pay' do 
    it "does stuff" do 
     # ... 

     transaction.pay 

     # ... 
    end 
    end 
end 

Вы заметите, что я необходим только файл транзакций - это поможет вам быть в курсе того, что другие классы зависящих от него, потому что вы 'll (в идеале) заглушить константы или, если необходимо, потребует других файлов. Это также улучшит время работы этой спецификации.

Кроме того, я только зарезал confirmed?, а не confirmed на счету double. С точки зрения Rails они означают одно и то же, но лучше использовать один из них последовательно, а не то и другое.

Если у вас есть тонна настроек (много констант и двойных тестов), я бы воспринял это как признак того, что этот класс транзакций, вероятно, необходимо разбить на несколько более конкретных классов.

Смежные вопросы