How to test arguments going into a mailer method?

Hi,

So I am not really interested in testing the content of the actual body
of an
outgoing email. I trust that Rails’ internal mechanisms work, however
recently
I came across some code that did something that I did want to test:


class PaypalProcessor

def send_email
Notifier.paypal_error(@errors,
@params.merge(decoded_custom_params)).deliver
end

end


… I simply wanted to verify that the variables being passed into my
ActionMailer::Base subclass are exactly what I expect them to be. I
felt that
this is pretty much all that I need to test (other than verifying that
the
actual email will be sent). So I wrote the following test:


before :each do
@encoded = Base64.encode64s({ :post_id => @post.id, :user_id =>
@user.id }).to_json
@processor = PaypalProcessor.new(:params => { :custom => @encoded,
:foo => “bar” })
end

it “sends an email to notify us of invalid data” do
@processor.should_not be_valid

Notifier.expects(:new).with(:paypal_error, @errors, { :post_id =>
@post.id,
:user_id =>
@user.id,
:foo => “bar”,
:custom =>
@encoded })

note: I wrote the above expectation that way based off of what I saw

in

ActionMailer::Base’s code… It uses method missing and does:

new(method, *args).message

lambda { @processor.send_email }.should
change(ActionMailer::Base.deliveries, :count).by(1)
end


I get this failure:

  1. PaypalParamProcessor validation sends an email to notify us of
    invalid data
    Failure/Error: lambda { @processor.send_email }.should
    change(ActionMailer::Base.deliveries, :count).by(1)
    Mocha::ExpectationError:
    unexpected invocation: Notifier.new(:paypal_error, [‘paypal did
    not verify the transaction!’, ‘paypal notified us of a payment with an
    invalid gross amount!’, ‘paypal gave a currency code other than USD!’,
    ‘paypal shows this transaction as belonging to another business!’],
    {:post_id => 430, :user_id => 538, :foo => ‘bar’, :custom =>
    ‘eyJwb3N0X2lkIjo0MzAsInVzZXJfaWQiOjUzOH0=’})
    unsatisfied expectations:
    • expected exactly once, not yet invoked:
      Notifier.new(:paypal_error, nil, {:post_id => 430, :user_id => 538, :foo
      => ‘bar’, :custom => ‘eyJwb3N0X2lkIjo0MzAsInVzZXJfaWQiOjUzOH0=’})
      satisfied expectations:
    • allowed any number of times, invoked once: #<Mock:Fancy Notify
      Object>.acknowledge(any_parameters)
    • allowed any number of times, invoked once: #<Mock:Fancy Notify
      Object>.complete?(any_parameters)
    • allowed any number of times, invoked once: #<Mock:Fancy Notify
      Object>.gross(any_parameters)
    • allowed any number of times, not yet invoked: #<Mock:Fancy
      Notify Object>.acknowledge(any_parameters)
    • allowed any number of times, invoked once:
      ActiveMerchant::Billing::Integrations::Paypal::Notification.new(any_parameters)

    ./lib/paypal_param_processor.rb:43:in `send_email’

    ./spec/lib/paypal_param_processor_spec.rb:63

    ./spec/lib/paypal_param_processor_spec.rb:63


So, obviously my approach isn’t so great. Can anyone assist me with a
better way to do this?

Patrick J. Collins
http://collinatorstudios.com

How about this?

paypal_error = mock(‘paypal_error’)
paypal_error.should_receive(:deliver)
Notifier.should_receive(:paypal_error).with(@errors, hash_including({
:post_id => @post.id,
:user_id =>
@user.id,
:foo => “bar”,
:custom =>
@encoded })).and_yield(paypal_error)

Mvh
Morten Mller Riis