2016-10-24 6 views
2

У меня есть объект, который сохраняет модель и запускает фоновое задание.Проверьте последовательность сообщений, отправленных на разные объекты/классы

Class UseCase 
    ... 
    def self.perform 
    @account.save 
    BackgroundJob.perform_later(@account.id) 
    end 
end 

В моей спецификации я хотел бы отдельно протестировать, что оба сообщения отправляются.

Я начал с чем-то вроде

it 'saves the account' do 
    expect_any_instance_of(Account).to receive(:save) 
    UseCase.perform(account) 
end 

И это работало хорошо, когда я был просто сохранение счета в perform. Но когда я добавил фоновую работу, спецификация больше не проходит, так как теперь Couldn't find Account without an ID.

Как я могу проверить (в RSped 3.5) отдельно, что оба сообщения отправлены?

UPDATE

it 'runs the job' do 
expect(BackgroundJob).to receive(:perform_later).with(instance_of(Fixnum)) 
UseCase.perform(account) 
end 

проходит, так что я предполагаю, что счет правильно сохранен.

Однако, когда я пытаюсь осмотреть @account

def self.perform 
@account.save 
byebug 
BackgroundJob.perform_later(@account.id) 
end 

В 'сохраняет счет', я получаю

(byebug) @account 
#<Account id: nil, full_name: "john doe" ...> 

В 'запускает работу', я получаю

(byebug) @account 
#<Account id: 1, full_name: "john doe" ...> 

Ожидание составляет @account a test double, поэтому в первом spec задание не может получить идентификатор.

Благодаря

+0

У вас есть спецификация, которая проверяет, что '@ account.save' фактически возвращает' true'? Я думаю, '@account.save' возвращает 'false', иначе учетная запись недействительна, не была сохранена и, следовательно, не имеет присвоенного' id'. – spickermann

+0

Я верю @spickermann правильно. Я добавил ответ, чтобы объяснить разницу между 'save!' И 'save'. Надеюсь, это поможет вам –

ответ

0

Ошибка Couldn't find Account without an ID на самом деле очень полезно, учитывая код, который вы имеете в вашем методе perform.

Этот вопрос упоминается в комментариях, но я уточню немного дальше.

Вы используете @account.save (я предполагаю, что @account является ActiveRecord объект), который по определению будет возвращать true/false при запуске (see documentation)

То, что вы, вероятно, хотите, чтобы использовать save! вместо поскольку она поднимет ActiveRecord::RecordInvalid Ошибка и прекратить выполнение, а не инициировать ошибку, которую вы указали ранее. (Бросить binding.pry в метод и обратите внимание на то, что @account является при попытке вызвать .id)

При изменении в save! вы можете добавить тест для случая, когда спасти может не (отсутствует атрибут, и т.д.). Может выглядеть примерно так

it 'should raise error when trying to save invalid record' do 
    # do something to invalidate @account 
    @account.username = nil 
    expect { UseCase.perform(@account) }.to raise_error(ActiveRecord::RecordInvalid) 
    #confirm that no messages were sent 
end 

Надеюсь, это поможет вам! GL и дайте мне знать, если у вас есть вопросы/нужна дополнительная помощь с rspec

+0

Спасибо за ответ. На самом деле я не понимаю, если вы предлагаете, чтобы моя учетная запись не была сохранена или она сохранена, но 'save' не возвращает то, что я хочу. – macsig

+0

, пожалуйста, ознакомьтесь с документацией, которую я связал. Если 'save' возвращает false, то ваша запись не была сохранена в БД (отсюда и отсутствие идентификатора) –