Rails/Rspec: Testing delayed_job mails

前端 未结 5 814
你的背包
你的背包 2021-02-01 17:37

Just wondering how to test that actionmailer requests are actually sent to the delayed_job que in rspec.

I would have assumed it was quite simple, but my delayed_job que

相关标签:
5条回答
  • 2021-02-01 17:53

    @zetetic I think we have to pass block in change method here.

    It shoulb be like this:

    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 讨论(0)
  • 2021-02-01 17:55

    This thread is a bit old, but here is my go at it:

    Create a function expect_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
    

    Then simply call it before checking if the callback has done its job. eg:

    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
    

    This seems to work on my side, and allows me to run both my delayed jobs and my methods.

    0 讨论(0)
  • 2021-02-01 17:59

    You can also follow the convention (from Railscast 275) of

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

    but instead do this:

        Delayed::Job.last.handler.should have_content(user.email)
    
    0 讨论(0)
  • 2021-02-01 18:00

    I think your mock object is somehow introducing an error -- it's hard to tell exactly how without seeing the definition of the mock_contact method.

    In any case, you might try something along these lines:

      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
    

    or the sexier version (caveat: I always end up doing it the non-sexy way):

      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 讨论(0)
  • 2021-02-01 18:01

    You can also test what the jobs will do by running them or turning off queuing.

    Tweak config whenever you want (i.e. in a before :each block).

    Delayed::Worker.delay_jobs = false
    

    or perform your saved jobs

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

    I have been using this method happily for a while. For one thing, using the new any_instance support in RSpec, you can test your delayed methods effects directly. However, I've found tests that use work_off to be slow.

    What I usually do now is:

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

    Then I have a separate spec for my_delayed_method. This is much faster, and probably better unit testing practice -- particularly for controllers. Though if you're doing request specs or other integration-level specs, then you probably still want to use work_off.

    0 讨论(0)
提交回复
热议问题