Rake test equivalent for ActionMailer::TestHelper? - ruby-on-rails

We have recently migrated from sending emails with deliver_now to deliver_later. So that queued emails aren't lost when the system restarts, we implement this with Sidekiq.
When we used deliver_now, our Rake tests could test the sending of an email with
assert_equal 1, ActionMailer::Base.deliveries.count
For Rspec there is the assert_enqueued_emails method to test whether or not emails are queued. Is there an equivalent for Rake test?

You can use the have_enqueued_mail matcher (documentation). Then your spec would use something like the following.
have_enqueued_mail(MyMailer, :my_particular_email).once

The solution was quite simple, once I knew what to do:
Add the line include ActionMailer::TestHelper to the start of the test file
Execute the method perform_enqueued_jobs after all emails were queued.
After that, all the old tests worked fine.
See https://api.rubyonrails.org/classes/ActiveJob/TestHelper.html#method-i-perform_enqueued_jobs

Related

Q:How to test ActionMailer deliver_later with Turnip,capybara and Gherkin

def deliver_mail
ServiceMailer.activation().deliver_later
end
deliver_mail method is called from some controller.
I want to test like below - feature test using cucumber and capybara.
step 'push next button' do
find("input.submit").click
end
Feature: Sending a mail to user
Scenario: mail to a user
When I push next button
Then mail should be sent to a user
actually, when 'push next button' is pushed, mail is sent by deliver_mail method.
when I use deliver_now instead of deliver_later, I can test the code above.
but after I change deliver_now to deliver_later, I can not test.
so I referenced below.
http://chriswarren.github.io/rpsec/testing/2015/03/13/testing-emails-and-active-job-in-rspec-feature-tests.html
I tried to include 'ActiveJob::TestHelper' like 'include ActiveJob::TestHelper' in spec file.
and i modified step file like this.
step 'push next button' do
 perform_enqueued_jobs do
find("input.submit").click
 end
end
but still doesn't work.
any hint and advice please.
I am using Delayed::Job for sending emails in a background, so when I test sending emails, I have two separate kinds of tests:
1) rspec - to check email body (in general, the method inside mailer) and sending the email itself
2) cucumber - to check if the email job was queued
In cucumber, I have the following code:
Then(/^A welcome email will be sent$/) do
expect(Delayed::Job.count).to eq(1)
end
I think there is no need to check anything else from the cucumber.
I would recommend not delaying jobs in test, and then checking the results of whatever DJ was supposed to run.
# rails_helper.rb
Delayed::Worker.delay_jobs = false

Testing Resque + Redis in RSpec

I am using Redis + Resque in production and want to test that jobs are getting queued and run properly. I am looking for something like this
Resque.jobs(:queue_name).size.should == 0
post :some_action # This action causes a Resque job to be enqueued
# Test Enqueuing
Resque.jobs(:queue_name).size.should == 1
Resque.jobs(:queue_name).last.klass.should == "MyJob"
Resque.jobs(:queue_name).last.args.should == [1, "Arg_2"]
# Test performing
Resque.jobs(:queue_name).perform_all
# test the effect of running the job
How do I start Redis + Resque in test environment? I don't people to manually run a redis server all the time. I have tried the solution where you try and run the redis server in config.before(:suite) but the redis-server never starts up in time and the Resque complains that it can't connect to Redis.
I have tried using Resque.inline but 1) It doesnt let me test that the Job was enqueued 2) It always enqueues the job inside the :inline queue (I want to test that the job ends up in the correct queue).
Personally, I rely on gems which I include in my project, including Resque and Redis, to be tested by the developers who write them. As a result, I do not include testing them in my test suite. For example, when choosing a gem for my application, I look at the gem's documentation to see if TravisCI / Code Climate / etc. statistics are included and if the project is "green." If it is, I use it. If it's not, I look for an earlier (e.g. more stable) version, or look for alternatives. In the case of Resque and Redis for Rails, both of these are well maintained and popular, thus extremely stable.
For my apps, I simply write tests where I present expectations of messages being called to Resque / Redis. For example:
it "should make a call to Resque for #my_job" do
expect(Resque).to_receive(:enqueue).with(SomeJob, args)
my_method_which_calls_resque
end
Then, assuming that you have a method which you are testing called my_method_which_calls_resque that looks something like:
def my_method_which_calls_resque
...
Resque.enqueue(SomeJob, args)
...
end
This test should be successful.
For additional documentation on messages and setting RSpec expectations, see RelishApp's docs on message expectations.
Then, if you wish to test your code within the Resque job itself, you can create a RSpec test for your job. Example:
# spec/lib/jobs/some_job_spec.rb
describe Jobs::SomeJob do
describe "#perform" do
it "should update someone's account" do
...
end
end
end

ActionMailer::Base.deliveries empty when using delayed_job

I'm using delayed_job to send emails in a Rails app and I'd like to test the email sending locally. Normally what I do is just set the mailer config to :test and then take a peek at ActionMailer::Base.deliveries, but the problem is when I call MyMailer.delay.some_email instead of MyMailer.some_email.deliver, the email never gets added to deliveries. I assume it's because I'm not longer calling "deliver", but you're not supposed to call "deliver" when using delayed_job.
All my production emails work fine. It's only the testing ones that don't.
Thoughts?
The jobs are not being worked off in the test environment because there's no jobs runner working. You need to instead check that the job has been added to the queue.
# Call the function
assert_not_equal Delayed::Job.count, 0, "Jobs have been added to the queue"
You can then test the job works by working it off, like so:
Delayed::Worker.new.work_off 1
# Check the job has been done as expected

How can i send emails with delayed_job

I'm trying to use delayed_job to send emails from an input form. In my view i have replaced the line
Emailer.deliver_signup(#usercontact)
with
Emailer.send_later(:deliver_signup, #usercontact)
but when i run the job with rake jobs:work, i get: undefined method 'deliver_signup' for "CLASS:Emailer":String
What am I doing wrong? (Note that the code works without delayed_job)
Delayed job mailer might help rather than trying to implement the details yourself.

How can I see what actually happens when a Test::Unit test runs?

In a Rails application I have a Test::Unit functional test that's failing, but the output on the console isn't telling me much.
How can I view the request, the response, the flash, the session, the variables set, and so on?
Is there something like...
rake test specific_test_file --verbose
You can add puts statements to your test case as suggested, or add calls to Rails.logger.debug() to your application code and watch your log/development.log to trace through what's happening.
In your test you have access to a bunch of resources you can user to debug your test.
p #request
p #response
p #controller
p flash
p cookie
p session
Also, remember that your action should be as simple as possibile and all the specific action execution should be tested by single Unit test.
Functional test should be reserved to the the overall action execution.
What does it mean in practice? If something doesn't work in your action, and your action calls 3 Model methods, you should be able to easily isolate the problem just looking at the unit tests. If one (or more) unit test fails, then you know which method is the guilty.
If all the unit tests pass, then the problem is the action itself but it should be quite easy to debug since you already tested the methods separately.
in the failing test use p #request etc. its ugly, but it can work
An answer to a separate question suggested
rake test TESTOPTS=-v
The slick way is to use pry and pry-nav gems. Be sure to include them in your test gem group. I use them in the development group as well. The great thing about pry and pry nav is you can step through your code with a console, so you can not only see the code as it's executed, but you can also enter console commands during the test.
You just enter binding.pry in the places in the code you want to trigger the console. Then using the 'step' command, you can move line by line through the code as it's executed.

Resources