Good morning (Pacific Time). I have a controller action that, as a side-effect, sends an email to an administrator. I want it to do something like this: specify "when someone successfully signs up, an email should be sent to the administrator with the person''s contact page" do post :signup, {...lots o'' params} response should_be success # here''s where I want to see whether email was sent. Of course, the code is bogus. email.body.should have_tag(:p, :content => /page=/) end Is there some way to reach in and grab the message (what I''ve written as "email" above) so I can test the various parameters such as the "to" array and the email contents? I''m most interested in whether the controller/mailer interaction is working properly. Also, can I use the DOM select expectations or is it a simple matcher? Thanks
On Feb 4, 2007, at 1:53 PM, s.ross wrote:> Good morning (Pacific Time). I have a controller action that, as a > side-effect, sends an email to an administrator. I want it to do > something like this: > > specify "when someone successfully signs up, an email should be sent > to the administrator with the person''s contact page" do > post :signup, {...lots o'' params} > response should_be success > > # here''s where I want to see whether email was sent. Of course, > the code is bogus. > email.body.should have_tag(:p, :content => /page=/) > end > > Is there some way to reach in and grab the message (what I''ve written > as "email" above) so I can test the various parameters such as the > "to" array and the email contents? I''m most interested in whether the > controller/mailer interaction is working properly. Also, can I use > the DOM select expectations or is it a simple matcher?On my first Rails project, I had to test whether a controller sent email when a job application was submitted. Fortunately, ActionMailer doesn''t deliver email when running in a test environment. Rather, it records deliveries and makes them available via ActionMailer::Base.deliveries. I demonstrate this below. Note that the chapter on ActionMailer in AWDwR was very helpful to me, since it described a couple of ways to test sending email. Anyway, here''s the code. Perhaps you can translate it into some specs. Craig require File.dirname(__FILE__) + ''/../test_helper'' require ''jobs_controller'' # Re-raise errors caught by the controller. class JobsController; def rescue_action(e) raise e end; end class JobsControllerTest < Test::Unit::TestCase fixtures #... def setup #... @emails = ActionMailer::Base.deliveries @emails.clear end def test_submit_application post :submit_application, :job_application => { # lots of params } assert_response :success assert_template ''submit_application'' assert_equal(2, @emails.size) email = @emails.first assert_match(/Confirm/, email.subject) assert_equal(''john at doe.com'', email.to()[0]) email = @emails[1] assert_match(/Resume received/, email.subject) assert_equal(''jobs at host.com'', email.to()[0]) end end
Yes, this works in the Test::Unit framework, but the rSpec behavior specing is -- to me -- different in spirit. My scenario is less about testing whether the mailer should send mail than it is about whether the action should trigger an email and then what the email should contain. I settled on this hack: specify "should send a ping when a signup occurs" do post :signup, {"member"=>{ "email_confirmation"=>"joe at schmoe.com", "last"=>"Schmoe", "first"=>"Joe", "phone"=>"111-222-3333", "working_with_agent"=>"0", "preferred_contact_method"=>"email", "agent_name"=>"", "email"=>"joe at schmoe.com"}, "projects"=>["3"]} response.should be_success email = ActionMailer::Base.deliveries[0] email.body.should include(''joe at schmoe.com'') email.body.should include(projects(:trace).name) email.body.should include(''member/show'') email.to.should include(''webmaster at test.host'') end end The code works, but relies on me knowing something about how ActionMailer collects emails in test mode. My question is: Should my spec presume this much knowledge or is there a better way to accomplish it? Steve On Feb 4, 2007, at 11:56 AM, Craig Demyanovich wrote:> On Feb 4, 2007, at 1:53 PM, s.ross wrote: > >> Good morning (Pacific Time). I have a controller action that, as a >> side-effect, sends an email to an administrator. I want it to do >> something like this: >> >> specify "when someone successfully signs up, an email should be sent >> to the administrator with the person''s contact page" do >> post :signup, {...lots o'' params} >> response should_be success >> >> # here''s where I want to see whether email was sent. Of course, >> the code is bogus. >> email.body.should have_tag(:p, :content => /page=/) >> end >> >> Is there some way to reach in and grab the message (what I''ve written >> as "email" above) so I can test the various parameters such as the >> "to" array and the email contents? I''m most interested in whether the >> controller/mailer interaction is working properly. Also, can I use >> the DOM select expectations or is it a simple matcher? > > On my first Rails project, I had to test whether a controller sent > email when a job application was submitted. Fortunately, ActionMailer > doesn''t deliver email when running in a test environment. Rather, it > records deliveries and makes them available via > ActionMailer::Base.deliveries. I demonstrate this below. Note that > the chapter on ActionMailer in AWDwR was very helpful to me, since it > described a couple of ways to test sending email. Anyway, here''s the > code. Perhaps you can translate it into some specs. > > Craig > > > > require File.dirname(__FILE__) + ''/../test_helper'' > require ''jobs_controller'' > > # Re-raise errors caught by the controller. > class JobsController; def rescue_action(e) raise e end; end > > class JobsControllerTest < Test::Unit::TestCase > fixtures #... > > def setup > #... > @emails = ActionMailer::Base.deliveries > @emails.clear > end > > def test_submit_application > post :submit_application, :job_application => { > # lots of params > } > > assert_response :success > assert_template ''submit_application'' > > assert_equal(2, @emails.size) > > email = @emails.first > assert_match(/Confirm/, email.subject) > assert_equal(''john at doe.com'', email.to()[0]) > > email = @emails[1] > assert_match(/Resume received/, email.subject) > assert_equal(''jobs at host.com'', email.to()[0]) > end > end > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
Steve - are you using the RSpec trunk? If you are, AND your email is html email, you can use this right now: response.should send_email { with_tag("div", "joe at shmoe.com") with_tag("div", projects(:trace).name) with_tag("div", member/show) } There is no specific support yet for email headers, nor raw text, though I can see now there is a need for that and will raise the appropriate RFE. David On 2/4/07, s.ross <cwdinfo at gmail.com> wrote:> Yes, this works in the Test::Unit framework, but the rSpec behavior > specing is -- to me -- different in spirit. My scenario is less about > testing whether the mailer should send mail than it is about whether > the action should trigger an email and then what the email should > contain. I settled on this hack: > > specify "should send a ping when a signup occurs" do > post :signup, {"member"=>{ > "email_confirmation"=>"joe at schmoe.com", > "last"=>"Schmoe", > "first"=>"Joe", > "phone"=>"111-222-3333", > "working_with_agent"=>"0", > "preferred_contact_method"=>"email", > "agent_name"=>"", > "email"=>"joe at schmoe.com"}, "projects"=>["3"]} > > response.should be_success > email = ActionMailer::Base.deliveries[0] > email.body.should include(''joe at schmoe.com'') > email.body.should include(projects(:trace).name) > email.body.should include(''member/show'') > email.to.should include(''webmaster at test.host'') > end > end > > The code works, but relies on me knowing something about how > ActionMailer collects emails in test mode. My question is: Should my > spec presume this much knowledge or is there a better way to > accomplish it? > > Steve > > On Feb 4, 2007, at 11:56 AM, Craig Demyanovich wrote: > > > On Feb 4, 2007, at 1:53 PM, s.ross wrote: > > > >> Good morning (Pacific Time). I have a controller action that, as a > >> side-effect, sends an email to an administrator. I want it to do > >> something like this: > >> > >> specify "when someone successfully signs up, an email should be sent > >> to the administrator with the person''s contact page" do > >> post :signup, {...lots o'' params} > >> response should_be success > >> > >> # here''s where I want to see whether email was sent. Of course, > >> the code is bogus. > >> email.body.should have_tag(:p, :content => /page=/) > >> end > >> > >> Is there some way to reach in and grab the message (what I''ve written > >> as "email" above) so I can test the various parameters such as the > >> "to" array and the email contents? I''m most interested in whether the > >> controller/mailer interaction is working properly. Also, can I use > >> the DOM select expectations or is it a simple matcher? > > > > On my first Rails project, I had to test whether a controller sent > > email when a job application was submitted. Fortunately, ActionMailer > > doesn''t deliver email when running in a test environment. Rather, it > > records deliveries and makes them available via > > ActionMailer::Base.deliveries. I demonstrate this below. Note that > > the chapter on ActionMailer in AWDwR was very helpful to me, since it > > described a couple of ways to test sending email. Anyway, here''s the > > code. Perhaps you can translate it into some specs. > > > > Craig > > > > > > > > require File.dirname(__FILE__) + ''/../test_helper'' > > require ''jobs_controller'' > > > > # Re-raise errors caught by the controller. > > class JobsController; def rescue_action(e) raise e end; end > > > > class JobsControllerTest < Test::Unit::TestCase > > fixtures #... > > > > def setup > > #... > > @emails = ActionMailer::Base.deliveries > > @emails.clear > > end > > > > def test_submit_application > > post :submit_application, :job_application => { > > # lots of params > > } > > > > assert_response :success > > assert_template ''submit_application'' > > > > assert_equal(2, @emails.size) > > > > email = @emails.first > > assert_match(/Confirm/, email.subject) > > assert_equal(''john at doe.com'', email.to()[0]) > > > > email = @emails[1] > > assert_match(/Resume received/, email.subject) > > assert_equal(''jobs at host.com'', email.to()[0]) > > end > > end > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 2/4/07, David Chelimsky <dchelimsky at gmail.com> wrote:> Steve - are you using the RSpec trunk? > > If you are, AND your email is html email, you can use this right now: > > response.should send_email { > with_tag("div", "joe at shmoe.com") > with_tag("div", projects(:trace).name) > with_tag("div", member/show) > }I forgot to mention that you''ll need this in setup/teardown when interacting w/ mail: setup do ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true ActionMailer::Base.deliveries = [] end teardown ActionMailer::Base.deliveries.clear end This email support is from a port of assert_select, and that''s how assert_select works.> > There is no specific support yet for email headers, nor raw text, > though I can see now there is a need for that and will raise the > appropriate RFE. > > David > > On 2/4/07, s.ross <cwdinfo at gmail.com> wrote: > > Yes, this works in the Test::Unit framework, but the rSpec behavior > > specing is -- to me -- different in spirit. My scenario is less about > > testing whether the mailer should send mail than it is about whether > > the action should trigger an email and then what the email should > > contain. I settled on this hack: > > > > specify "should send a ping when a signup occurs" do > > post :signup, {"member"=>{ > > "email_confirmation"=>"joe at schmoe.com", > > "last"=>"Schmoe", > > "first"=>"Joe", > > "phone"=>"111-222-3333", > > "working_with_agent"=>"0", > > "preferred_contact_method"=>"email", > > "agent_name"=>"", > > "email"=>"joe at schmoe.com"}, "projects"=>["3"]} > > > > response.should be_success > > email = ActionMailer::Base.deliveries[0] > > email.body.should include(''joe at schmoe.com'') > > email.body.should include(projects(:trace).name) > > email.body.should include(''member/show'') > > email.to.should include(''webmaster at test.host'') > > end > > end > > > > The code works, but relies on me knowing something about how > > ActionMailer collects emails in test mode. My question is: Should my > > spec presume this much knowledge or is there a better way to > > accomplish it? > > > > Steve > > > > On Feb 4, 2007, at 11:56 AM, Craig Demyanovich wrote: > > > > > On Feb 4, 2007, at 1:53 PM, s.ross wrote: > > > > > >> Good morning (Pacific Time). I have a controller action that, as a > > >> side-effect, sends an email to an administrator. I want it to do > > >> something like this: > > >> > > >> specify "when someone successfully signs up, an email should be sent > > >> to the administrator with the person''s contact page" do > > >> post :signup, {...lots o'' params} > > >> response should_be success > > >> > > >> # here''s where I want to see whether email was sent. Of course, > > >> the code is bogus. > > >> email.body.should have_tag(:p, :content => /page=/) > > >> end > > >> > > >> Is there some way to reach in and grab the message (what I''ve written > > >> as "email" above) so I can test the various parameters such as the > > >> "to" array and the email contents? I''m most interested in whether the > > >> controller/mailer interaction is working properly. Also, can I use > > >> the DOM select expectations or is it a simple matcher? > > > > > > On my first Rails project, I had to test whether a controller sent > > > email when a job application was submitted. Fortunately, ActionMailer > > > doesn''t deliver email when running in a test environment. Rather, it > > > records deliveries and makes them available via > > > ActionMailer::Base.deliveries. I demonstrate this below. Note that > > > the chapter on ActionMailer in AWDwR was very helpful to me, since it > > > described a couple of ways to test sending email. Anyway, here''s the > > > code. Perhaps you can translate it into some specs. > > > > > > Craig > > > > > > > > > > > > require File.dirname(__FILE__) + ''/../test_helper'' > > > require ''jobs_controller'' > > > > > > # Re-raise errors caught by the controller. > > > class JobsController; def rescue_action(e) raise e end; end > > > > > > class JobsControllerTest < Test::Unit::TestCase > > > fixtures #... > > > > > > def setup > > > #... > > > @emails = ActionMailer::Base.deliveries > > > @emails.clear > > > end > > > > > > def test_submit_application > > > post :submit_application, :job_application => { > > > # lots of params > > > } > > > > > > assert_response :success > > > assert_template ''submit_application'' > > > > > > assert_equal(2, @emails.size) > > > > > > email = @emails.first > > > assert_match(/Confirm/, email.subject) > > > assert_equal(''john at doe.com'', email.to()[0]) > > > > > > email = @emails[1] > > > assert_match(/Resume received/, email.subject) > > > assert_equal(''jobs at host.com'', email.to()[0]) > > > end > > > end > > > > > > _______________________________________________ > > > rspec-users mailing list > > > rspec-users at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > >
I''m running trunk and tried this. I put a pastie on: http://pastie.caboo.se/37928 Everything up to line 37 passes, but there it fails. The actual html sent to the mailer is: <html> <body> <p><strong>Joe Schmoe</strong> signed the form and expressed interest in the following project(s): #snip#. You may reach Joe at: (111) 222-3333 or email at joe at schmoe.com.</p> <p>Full contact information has been saved to your database and you may view it at <a href="http://test.host/member/show/25">here</a>.</p> </body> </html> Perhaps I misunderstand how to use with_tag. I''ve tried: with_tag("p", "joe at schmoe.com") and I tried: with_tag("p", /joe at schmoe.com/) At this point, I''m really guessing but I know the results are good but the spec isn''t satisfied. Thoughts? On Feb 4, 2007, at 1:47 PM, David Chelimsky wrote:> On 2/4/07, David Chelimsky <dchelimsky at gmail.com> wrote: >> Steve - are you using the RSpec trunk? >> >> If you are, AND your email is html email, you can use this right now: >> >> response.should send_email { >> with_tag("div", "joe at shmoe.com") >> with_tag("div", projects(:trace).name) >> with_tag("div", member/show) >> } > > I forgot to mention that you''ll need this in setup/teardown when > interacting w/ mail: > > setup do > ActionMailer::Base.delivery_method = :test > ActionMailer::Base.perform_deliveries = true > ActionMailer::Base.deliveries = [] > end > > teardown > ActionMailer::Base.deliveries.clear > end > > This email support is from a port of assert_select, and that''s how > assert_select works. > >> >> There is no specific support yet for email headers, nor raw text, >> though I can see now there is a need for that and will raise the >> appropriate RFE. >> >> David >> >> On 2/4/07, s.ross <cwdinfo at gmail.com> wrote: >>> Yes, this works in the Test::Unit framework, but the rSpec behavior >>> specing is -- to me -- different in spirit. My scenario is less >>> about >>> testing whether the mailer should send mail than it is about whether >>> the action should trigger an email and then what the email should >>> contain. I settled on this hack: >>> >>> specify "should send a ping when a signup occurs" do >>> post :signup, {"member"=>{ >>> "email_confirmation"=>"joe at schmoe.com", >>> "last"=>"Schmoe", >>> "first"=>"Joe", >>> "phone"=>"111-222-3333", >>> "working_with_agent"=>"0", >>> "preferred_contact_method"=>"email", >>> "agent_name"=>"", >>> "email"=>"joe at schmoe.com"}, "projects"=>["3"]} >>> >>> response.should be_success >>> email = ActionMailer::Base.deliveries[0] >>> email.body.should include(''joe at schmoe.com'') >>> email.body.should include(projects(:trace).name) >>> email.body.should include(''member/show'') >>> email.to.should include(''webmaster at test.host'') >>> end >>> end >>> >>> The code works, but relies on me knowing something about how >>> ActionMailer collects emails in test mode. My question is: Should my >>> spec presume this much knowledge or is there a better way to >>> accomplish it? >>> >>> Steve >>> >>> On Feb 4, 2007, at 11:56 AM, Craig Demyanovich wrote: >>> >>>> On Feb 4, 2007, at 1:53 PM, s.ross wrote: >>>> >>>>> Good morning (Pacific Time). I have a controller action that, as a >>>>> side-effect, sends an email to an administrator. I want it to do >>>>> something like this: >>>>> >>>>> specify "when someone successfully signs up, an email should be >>>>> sent >>>>> to the administrator with the person''s contact page" do >>>>> post :signup, {...lots o'' params} >>>>> response should_be success >>>>> >>>>> # here''s where I want to see whether email was sent. Of course, >>>>> the code is bogus. >>>>> email.body.should have_tag(:p, :content => /page=/) >>>>> end >>>>> >>>>> Is there some way to reach in and grab the message (what I''ve >>>>> written >>>>> as "email" above) so I can test the various parameters such as the >>>>> "to" array and the email contents? I''m most interested in >>>>> whether the >>>>> controller/mailer interaction is working properly. Also, can I use >>>>> the DOM select expectations or is it a simple matcher? >>>> >>>> On my first Rails project, I had to test whether a controller sent >>>> email when a job application was submitted. Fortunately, >>>> ActionMailer >>>> doesn''t deliver email when running in a test environment. >>>> Rather, it >>>> records deliveries and makes them available via >>>> ActionMailer::Base.deliveries. I demonstrate this below. Note that >>>> the chapter on ActionMailer in AWDwR was very helpful to me, >>>> since it >>>> described a couple of ways to test sending email. Anyway, here''s >>>> the >>>> code. Perhaps you can translate it into some specs. >>>> >>>> Craig >>>> >>>> >>>> >>>> require File.dirname(__FILE__) + ''/../test_helper'' >>>> require ''jobs_controller'' >>>> >>>> # Re-raise errors caught by the controller. >>>> class JobsController; def rescue_action(e) raise e end; end >>>> >>>> class JobsControllerTest < Test::Unit::TestCase >>>> fixtures #... >>>> >>>> def setup >>>> #... >>>> @emails = ActionMailer::Base.deliveries >>>> @emails.clear >>>> end >>>> >>>> def test_submit_application >>>> post :submit_application, :job_application => { >>>> # lots of params >>>> } >>>> >>>> assert_response :success >>>> assert_template ''submit_application'' >>>> >>>> assert_equal(2, @emails.size) >>>> >>>> email = @emails.first >>>> assert_match(/Confirm/, email.subject) >>>> assert_equal(''john at doe.com'', email.to()[0]) >>>> >>>> email = @emails[1] >>>> assert_match(/Resume received/, email.subject) >>>> assert_equal(''jobs at host.com'', email.to()[0]) >>>> end >>>> end >>>> >>>> _______________________________________________ >>>> rspec-users mailing list >>>> rspec-users at rubyforge.org >>>> http://rubyforge.org/mailman/listinfo/rspec-users >>> >>> _______________________________________________ >>> rspec-users mailing list >>> rspec-users at rubyforge.org >>> http://rubyforge.org/mailman/listinfo/rspec-users >>> >> > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
David-- I still don''t have this working (see my previous email with the pastie attached), but now have another ActionMailer/rSpec question. I''m spec''ing a different mailer model directly (instead of through the controller). It''s meant to be invoked through script/runner, so I won''t have a response object. I can see in the plugin source that there is assert_select_email support, but I''m pretty sure there is no expectation that starts with "assert." How would one spec something like: setup do ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true ActionMailer::Base.deliveries = [] MyMailer.trigger_emails # invokes model method to send 4 emails end specify "d''oh! should have a non-empty recipient list" do ActionMailer::Base.deliveries.size.should be(4) ActionMailer::Base.deliveries.each do |email| email.recipients.should_not be_empty end end specify "first email should have a list item with the name of the first guy" do ActionMailer::Base.deliveries[0].should select_tag(''li'', members (:joe).name) end The above code is truly bogus and doesn''t work. I''m trying to figure out where to get the messages and how to specify the expectations on them. Thanks, Steve On Feb 4, 2007, at 1:35 PM, David Chelimsky wrote:> Steve - are you using the RSpec trunk? > > If you are, AND your email is html email, you can use this right now: > > response.should send_email { > with_tag("div", "joe at shmoe.com") > with_tag("div", projects(:trace).name) > with_tag("div", member/show) > } > > There is no specific support yet for email headers, nor raw text, > though I can see now there is a need for that and will raise the > appropriate RFE. > > David >
On 2/5/07, s.ross <cwdinfo at gmail.com> wrote:> David-- > > I still don''t have this working (see my previous email with the > pastie attached), but now have another ActionMailer/rSpec question. > I''m spec''ing a different mailer model directly (instead of through > the controller). It''s meant to be invoked through script/runner, so I > won''t have a response object. > > I can see in the plugin source that there is assert_select_email > support, but I''m pretty sure there is no expectation that starts with > "assert." How would one spec something like: > > setup do > ActionMailer::Base.delivery_method = :test > ActionMailer::Base.perform_deliveries = true > ActionMailer::Base.deliveries = [] > MyMailer.trigger_emails # invokes model method to send 4 emails > end > > specify "d''oh! should have a non-empty recipient list" do > ActionMailer::Base.deliveries.size.should be(4) > ActionMailer::Base.deliveries.each do |email| > email.recipients.should_not be_empty > end > endassert_select doesn''t wrap this sort of access, so neither does the port. What you''ve got there is probably what I''d do. Anything that RSpec would provide would wrap that anyhow. One thing you can do slightly differently is this: ActionMailer::Base.should have(4).deliveries That''s in rspec core.> > specify "first email should have a list item with the name of the > first guy" do > ActionMailer::Base.deliveries[0].should select_tag(''li'', members > (:joe).name) > endThis one you shold be able to do like this: specify "first email should have a list item with the name of the first guy" do response.should be_email { with_tag(''li'', members(:joe).name) } end Hope that helps a little. David> > > The above code is truly bogus and doesn''t work. I''m trying to figure > out where to get the messages and how to specify the expectations on > them. > > Thanks, > > Steve > > > On Feb 4, 2007, at 1:35 PM, David Chelimsky wrote: > > > Steve - are you using the RSpec trunk? > > > > If you are, AND your email is html email, you can use this right now: > > > > response.should send_email { > > with_tag("div", "joe at shmoe.com") > > with_tag("div", projects(:trace).name) > > with_tag("div", member/show) > > } > > > > There is no specific support yet for email headers, nor raw text, > > though I can see now there is a need for that and will raise the > > appropriate RFE. > > > > David > > > > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Feb 5, 2007, at 1:52 PM, s.ross wrote:> David-- > > I still don''t have this working (see my previous email with the > pastie attached), but now have another ActionMailer/rSpec question. > I''m spec''ing a different mailer model directly (instead of through > the controller). It''s meant to be invoked through script/runner, so I > won''t have a response object.Steve, Your comments got me thinking about this again. First, there is the behavior that you expect your controller to exhibit: that certain actions send email. Second, there is the behavior that your ActionMailer::Base derivative should exhibit: that it creates email as you like. Furthermore, you write that you want to invoke an ActionMailer::Base derivative via script/runner instead of or in addition to a controller. Therefore, you should specify their respective behaviors independently of one another. I''m including a code snippet from _Agile Web Development with Rails, 2nd ed._, that shows an example of testing the ActionMailer::Base derivative by itself. I''m sure you can translate the test to a spec. require File.dirname(__FILE__) + ''/../test_helper'' require ''order_mailer'' class OrderMailerTest < Test::Unit::TestCase def setup @order = Order.new(:name =>"Dave Thomas", :email => "dave at pragprog.com") end def test_confirm response = OrderMailer.create_confirm(@order) assert_equal("Pragmatic Store Order Confirmation", response.subject) assert_equal("dave at pragprog.com", response.to[0]) assert_match(/Dear Dave Thomas/, response.body) end end Taking this approach will allow you to minimize the number of tests that you write to prove that the controller behaves as it should. Then, you can focus your attention on the ActionMailer::Base derivative alone for all the things you want to verify about the content of email. I hope this helps somehow. Regards, Craig
David/Craig-- Two tests are actually what I''m doing. I''m testing two separate mailers. The first is triggered as a side effect of an action. That mailer is inextricably intertwined with the controller, as it has to provide a URL to the page of someone who signed up, etc. I suppose I could mock the controller object, but does that really provide better results? The second mailer is, as mentioned, triggered from the command line and is being tested in a fashion similar to AWDROR''s. Here is the (acckkk!) code I settled on, which IMO violates a lot of OO principles. require File.dirname(__FILE__) + ''/../spec_helper.rb'' context "A MemberDigest" do fixtures :members setup do ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true ActionMailer::Base.deliveries = [] MemberDigest.trigger_emails # invokes model method to send 4 emails end specify "d''oh! should have a non-empty recipient list" do ActionMailer::Base.deliveries.size.should be(4) ActionMailer::Base.deliveries.inspect ActionMailer::Base.deliveries.each do |email| email.to_addrs.should_not be_empty end end specify "first email should have a list item with the name of the first guy" do ActionMailer::Base.deliveries.first.body.should_include(members (:existing_user_1).first) end teardown do ActionMailer::Base.deliveries.clear end end Comments? On Feb 5, 2007, at 11:22 AM, Craig Demyanovich wrote:> > On Feb 5, 2007, at 1:52 PM, s.ross wrote: > >> David-- >> >> I still don''t have this working (see my previous email with the >> pastie attached), but now have another ActionMailer/rSpec question. >> I''m spec''ing a different mailer model directly (instead of through >> the controller). It''s meant to be invoked through script/runner, so I >> won''t have a response object. > > Steve, > > Your comments got me thinking about this again. First, there is the > behavior that you expect your controller to exhibit: that certain > actions send email. Second, there is the behavior that your > ActionMailer::Base derivative should exhibit: that it creates email > as you like. Furthermore, you write that you want to invoke an > ActionMailer::Base derivative via script/runner instead of or in > addition to a controller. > > Therefore, you should specify their respective behaviors > independently of one another. I''m including a code snippet from > _Agile Web Development with Rails, 2nd ed._, that shows an example of > testing the ActionMailer::Base derivative by itself. I''m sure you can > translate the test to a spec. > > require File.dirname(__FILE__) + ''/../test_helper'' > require ''order_mailer'' > > class OrderMailerTest < Test::Unit::TestCase > def setup > @order = Order.new(:name =>"Dave Thomas", :email => > "dave at pragprog.com") > end > > def test_confirm > response = OrderMailer.create_confirm(@order) > assert_equal("Pragmatic Store Order Confirmation", > response.subject) > assert_equal("dave at pragprog.com", response.to[0]) > assert_match(/Dear Dave Thomas/, response.body) > end > end > > Taking this approach will allow you to minimize the number of tests > that you write to prove that the controller behaves as it should. > Then, you can focus your attention on the ActionMailer::Base > derivative alone for all the things you want to verify about the > content of email. I hope this helps somehow. > > Regards, > Craig > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
On Feb 5, 2007, at 2:45 PM, s.ross wrote:> David/Craig-- > > Two tests are actually what I''m doing. I''m testing two separate > mailers. The first is triggered as a side effect of an action. That > mailer is inextricably intertwined with the controller, as it has to > provide a URL to the page of someone who signed up, etc. I suppose I > could mock the controller object, but does that really provide better > results?Isolating the controller and mailer as much as possible is the best approach, IMHO. And, I don''t think any mailer has to be bound tightly to a controller. Here''s what I''d do. Specify each mailer in isolation, focusing on all the interesting bits of the email messages that the mailers will create. For example: context "An email for a new member" do ... specify "includes the URL used at sign up" do mail = MemberDigest.create_welcome(@member) mail.body.should_match /"#{@member.url}"/ end ... end Then I''d mock/stub the one mailer and verify that the controller uses it correctly. As a second option, I''d just let the controller use the mailer and verify that I had one delivery; I wouldn''t pick apart the delivery, though, since I''d be comfortable that I''d specified the mailer well enough already.> > The second mailer is, as mentioned, triggered from the command line > and is being tested in a fashion similar to AWDROR''s. Here is the > (acckkk!) code I settled on, which IMO violates a lot of OO > principles. > > require File.dirname(__FILE__) + ''/../spec_helper.rb'' > > context "A MemberDigest" do > fixtures :members > > setup do > ActionMailer::Base.delivery_method = :test > ActionMailer::Base.perform_deliveries = true > ActionMailer::Base.deliveries = [] > MemberDigest.trigger_emails # invokes model method to send 4 > emails > end > > specify "d''oh! should have a non-empty recipient list" do > ActionMailer::Base.deliveries.size.should be(4) > ActionMailer::Base.deliveries.inspect > ActionMailer::Base.deliveries.each do |email| > email.to_addrs.should_not be_empty > end > end > > specify "first email should have a list item with the name of the > first guy" do > ActionMailer::Base.deliveries.first.body.should_include(members > (:existing_user_1).first) > end > > teardown do > ActionMailer::Base.deliveries.clear > end > end > > Comments?Again, I''m tempted to specify the mailer in isolation and either trust that delivery will happen if I ask for it or specify delivery in isolation. Bear in mind that I might be missing something about this example, as my experience with Rails is still somewhat limited.> > > On Feb 5, 2007, at 11:22 AM, Craig Demyanovich wrote: > >> >> On Feb 5, 2007, at 1:52 PM, s.ross wrote: >> >>> David-- >>> >>> I still don''t have this working (see my previous email with the >>> pastie attached), but now have another ActionMailer/rSpec question. >>> I''m spec''ing a different mailer model directly (instead of through >>> the controller). It''s meant to be invoked through script/runner, >>> so I >>> won''t have a response object. >> >> Steve, >> >> Your comments got me thinking about this again. First, there is the >> behavior that you expect your controller to exhibit: that certain >> actions send email. Second, there is the behavior that your >> ActionMailer::Base derivative should exhibit: that it creates email >> as you like. Furthermore, you write that you want to invoke an >> ActionMailer::Base derivative via script/runner instead of or in >> addition to a controller. >> >> Therefore, you should specify their respective behaviors >> independently of one another. I''m including a code snippet from >> _Agile Web Development with Rails, 2nd ed._, that shows an example of >> testing the ActionMailer::Base derivative by itself. I''m sure you can >> translate the test to a spec. >> >> require File.dirname(__FILE__) + ''/../test_helper'' >> require ''order_mailer'' >> >> class OrderMailerTest < Test::Unit::TestCase >> def setup >> @order = Order.new(:name =>"Dave Thomas", :email => >> "dave at pragprog.com") >> end >> >> def test_confirm >> response = OrderMailer.create_confirm(@order) >> assert_equal("Pragmatic Store Order Confirmation", >> response.subject) >> assert_equal("dave at pragprog.com", response.to[0]) >> assert_match(/Dear Dave Thomas/, response.body) >> end >> end >> >> Taking this approach will allow you to minimize the number of tests >> that you write to prove that the controller behaves as it should. >> Then, you can focus your attention on the ActionMailer::Base >> derivative alone for all the things you want to verify about the >> content of email. I hope this helps somehow. >> >> Regards, >> Craig >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
Possibly Parallel Threads
- experimental rails story adapter in trunk
- testing to see if emails are sent out on exceptions
- Testing action mailer in functional tests - missing section in the book
- second assert_tag failling in rails integration test
- testing exception notification plugin with rspec