Rails / Rspec: тестирование писем delayed_job - PullRequest
24 голосов
/ 15 июня 2011

Просто интересно, как проверить, действительно ли запросы actionmailer отправляются в очередь delayed_job в rspec.

Я бы предположил, что это было довольно просто, но моя очередь delayed_job, похоже, не увеличивается.Код ниже:

Контроллер:

  def create
    @contact = Contact.new(params[:contact])
      if @contact.save
        contactmailer = ContactMailer
        contactmailer.delay.contact_message(@contact)
        redirect_to(contacts_url)
      else
        render :action => "new"
      end

Спецификация:

  it "queues mail when a contact is created" do
    expectedcount = Delayed::Job.count + 1
    Contact.stub(:new).with(mock_contact()) { mock_contact(:save => true) }
    post :create, :contact => mock_contact
    expectedcount.should eq(Delayed::Job.count)
  end

Как до, так и после вызова контроллера, Delayed :: Job.count возвращает 0Я попытался удалить условное выражение из контроллера, но все еще не могу увеличить отсроченное задание.

Любые предложения приветствуются - приветствие

Ответы [ 5 ]

48 голосов
/ 05 августа 2011

Вы также можете проверить, что будут делать задания, запустив их или отключив очередь.

Настройте конфигурацию, когда захотите (т.е. в блоке before :each).

Delayed::Worker.delay_jobs = false

или выполнить сохраненные задания

Delayed::Worker.new.work_off.should == [1, 0]

Я давно с удовольствием пользуюсь этим методом. Во-первых, используя новую поддержку any_instance в RSpec, вы можете напрямую протестировать эффекты отложенных методов. Тем не менее, я нашел тесты, которые используют work_off, чтобы быть медленным .

Что я обычно делаю сейчас:

mock_delay = double('mock_delay').as_null_object
MyClass.any_instance.stub(:delay).and_return(mock_delay)
mock_delay.should_receive(:my_delayed_method)

Тогда у меня есть отдельная спецификация для my_delayed_method. Это намного быстрее, и, вероятно, лучше практики модульного тестирования - особенно для контроллеров. Хотя, если вы выполняете спецификации запросов или другие спецификации уровня интеграции, вам, вероятно, все еще нужно использовать work_off.

16 голосов
/ 15 июня 2011

Я думаю, что ваш фиктивный объект как-то вносит ошибку - трудно точно сказать, как, не видя определения метода mock_contact.

В любом случае, вы можете попробовать что-то вроде этого:

  it "queues mail when a contact is created" do
    Contact.stub(:new) { mock_model(Contact,:save => true) }
    Delayed::Job.count.should == 0
    post :create, {}
    Delayed::Job.count.should == 1
  end

или более сексуальная версия ( предостережение: я всегда заканчиваю тем, что делаю это несексуальным образом ):

  it "queues mail when a contact is created" do
    Contact.stub(:new) { mock_model(Contact,:save => true) }
    expect {
      post :create, {}
    }.to change(Delayed::Job.count).by(1)
  end
9 голосов
/ 06 марта 2013

Вы также можете следовать соглашению (от Railscast 275 ) до

    ActionMailer::Base.deliveries.last.to.should == user.email

но вместо этого сделайте это:

    Delayed::Job.last.handler.should have_content(user.email)
0 голосов
/ 02 ноября 2016

@ zetetic Я думаю, что мы должны передать блок в методе изменения.

Это должно быть так:

it "queues mail when a contact is created" do
Contact.stub(:new) { mock_model(Contact,:save => true) }
expect {
    post :create, {}
  }.to change { Delayed::Job.count }.by(1)
end
0 голосов
/ 30 июня 2014

Эта тема немного устарела, но вот мое мнение:

Создайте функцию wait_jobs

def expect_jobs n, time = nil
  expect(Delayed::Job.count).to eq(n)
  Timecop.travel(time) unless time.nil?
  successes, failures = Delayed::Worker.new.work_off
  expect(successes).to eq(n)
  expect(failures).to eq(0)
  expect(Delayed::Job.count).to eq(0)
  Timecop.travel(Time.now) unless time.nil?
end

Затем просто позвоните, прежде чем проверять, сделал ли обратный вызов свою работу. например:

it "sends a chapter to the admin user" do
  post :chapter_to_user, { chapter: @book.chapters.first}
  expect_jobs(1)
  SubscribeMailer.should have(1).delivery
  SubscribeMailer.deliveries.should have(1).attachment
end

Это, кажется, работает на моей стороне и позволяет мне запускать оба моих отложенных задания и мои методы.

...