When implementing email functionality, the email_spec gem is something I’ve decided I can’t live without.
It makes it so easy to write RSpec specs and Cucumber features around your email that you have no excuse not to.
Today I’m going to go through an example how I recently used BDD to send an email in an app I was working on.
When I think about email and my Rails environments this is how I typically want them to behave.
test should not send emails and allow us to write specs or features against them
development should not send emails but provide a UI to view what would be sent on localhost
staging should not send emails but provide a UI to view what would be sent on a server
Let’s imagine we are working on a new startup in stealth mode. We want to generate buzz and prepare for a beta launch.
We’re hiding the fact its all vaporware with a splashy homepage where people can request an invitation to the beta and
records their email in our database. This is the same example as my article last week and there’s a
live demo at http://awesome-site-staging.heroku.com/.
What we’ll do today is not just record the email address but also send a “thanks for your interest” email to the user.
We’re going to do this in BDD fashion bouncing back and forth between Cucumber Scenarios and RSpec Unit Tests
Writing a cucumber scenario
While the scenario fails
Write a failing rspec spec
Write code to make it pass
The Cucumber scenario tells us what should be accomplished and when it fails it we use that to tell us what unit test we should write.
Adding the email_spec gem
We add it to our Gemfile
We bundle and use the email_spec generator to let it initialize itself.
There’s also a manual step to get cucumber to load the email_spec gem. We need to create a file features/support/email_spec.rb
Our first Cucumber Scenario
We know that when a user requests an invitation they should get an email so we write that requirement as a Cucumber Scenario.
features/request_an_invitation.feature
We run it and it tells us we have a couple of missing steps.
Oh right, the training wheels came off in cucumber-rails v1.1.1
and we don’t have web_steps.rb anymore. Let’s write these steps using capybara in features/step_definitions/invite_steps.rb
We run one more time and get a failure we expect. Its telling us we haven’t written any code to implement the scenario yet!
Dropping into RSpec unit tests
Our failing feature tells us what we need to implement so we drop down to the unit test level and start implementing it with TDD.
The feature tells us an email should be be generated so let’s go.
We’ll add to our invites_controller_spec specifying that it should create and deliver an InviteMailer.
spec/controllers/invites_controller_spec.rb
Of course we get an error uninitialized constant InviteMailer. We fix that by creating the mailer (it doesn’t do anything yet)
app/mailers/invite_mailer.rb
The error changes
We add the code to our controller to create and deliver the email in app/controllers/invites_controller.rb
Are we done?
Checking the Cucumber Scenario…
The RSpec unit tests pass now but the Cucumber features are still failing.
Duh our InviteMailer doesn’t do anything.
Back down to the unit tests
We write our spec/mailers/invite_mailer_spec.rb. We need to include some EmailSpec modules so we have access to its matchers.
Of course it fails because we still haven’t implemented anything. Let’s add some code to app/mailers/invite_mailer.rb
and we can use haml to format the body in app/views/invite_mailer/invite_requested.text.haml
We run the rake one more time and …
We’re Done
Everything passes - the specs and the features!
I hope you’ll consider using the email_spec gem and BDD the next time you have to add email to your app.