Использование rspec для тестирования ActionMailer с should_receive

У меня есть такой тест RSpec:

it "should ..." do
  # mailer = mock
  # mailer.should_receive(:deliver)
  Mailer.should_receive(:notification_to_sender)#.and_return(mailer)

  visit transactions_path
  expect do
    page.should_not have_css("table#transactions_list tbody tr")
    find('#some_button').click
    page.should have_css("table#transactions_list tbody tr", :count => 1)
  end.to change{Transaction.count}.by(1)
end

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

Я получил прокомментированные фрагменты из некоторых поисковых запросов в сети, но я действительно не понимаю, что он делает или почему это исправляет это. Кажется, должен быть более чистый способ проверки электронной почты без этого.

Кто-нибудь может пролить свет? Спасибо!

Я использую рельсы 3 и rspec-rails 2.10.1.


person Brian Armstrong    schedule 05.06.2012    source источник


Ответы (2)


Я думаю, вы хотите, чтобы экземпляр Mailer получал notification_to_sender, а не класс. Из API Rails

Вы никогда не создаете экземпляр класса почтовой программы. Вместо этого ваши методы экземпляра доставки автоматически заключаются в методы класса, начинающиеся со слова Deliver_, за которым следует имя метода почтовой программы, который вы хотите доставить. Определенный выше метод signup_notification доставляется путем вызова Notifier.deliver_signup_notification.

Поэтому я бы использовал

Mailer.any_instance.should_receive(:notification_to_sender)

Кроме того, если вам нужно получить последнее доставленное сообщение, используйте

ActionMailer::Base.deliveries.last

Думаю, это должно решить вашу проблему.

person Community    schedule 05.06.2012
comment
хм, я не уверен, почему, но все равно кажется, что ошибка :/ показанная ошибка не имеет смысла (из другой строки), но когда я комментирую строку should_receive, она снова работает. Ну что ж... переходим к более серьезным проблемам на данный момент. - person Brian Armstrong; 08.08.2012
comment
Фактически API ActionMailer изменился с Mailer.deliver_notification_to_sender в Rails 2.x на Mailer.notification_to_sender.deliver в Rails 3.0. Учитывая это изменение, методы экземпляра доставки больше не оборачивают в методы класса, поскольку без вызова доставки вы возвращаете экземпляр Mail::Message. - person MAP; 13.06.2013

Вероятно, вы вызываете Mailer.notification_to_sender.deliver в своем контроллере или, что еще лучше, выполняете фоновое задание. Я предполагаю, что notification_to_sender, вероятно, также принимает параметр.

В любом случае, когда вы вызываете метод notification_to_sender в Mailer, вы возвращаете экземпляр Mail::Message, в котором есть метод deliver. Если бы вы просто выполняли Mailer.notification_to_sender, не вызывая также deliver, вы могли бы запустить то, что у вас есть, с комментариями, и все было бы в порядке. Я предполагаю, что вы также звоните deliver.

В этом случае ваше сообщение об ошибке будет выглядеть примерно так

NoMethodError:
  undefined method `deliver' for nil:NilClass

Это потому, что nil большую часть времени является возвращаемым значением Ruby по умолчанию, которое также наследует Rails. Без указания частей mailer = mock и .and_return(mailer), когда контроллер выполняется в контексте теста, notification_to_sender вернет nil, и контроллер попытается вызвать deliver для этого объекта nil.

Решение, которое вы закомментировали, состоит в том, чтобы смоделировать возвращаемое значение notification_to_sender (обычно Mail::Message), а затем ожидать, что для него будет вызван метод deliver.

person MAP    schedule 13.06.2013