Well, I found the problem(s) and the solution was close to what some
suggestions had been. Here''s what I wound up doing.
First, mock files should have the same name as the model they are
replacing from app/models. So, in my case, I needed
test/mocks/test/notifier.rb instead of test/mocks/test/test_mailer.rb.
Second, the mock file needs to have "require models/[model]" first
(even though I''m only making changes to ActionMailer::Base, not the
Notifier class derived from it).
Then, in this file, I have:
ActionMailer::Base.class_eval {
@@inject_error = false
cattr_accessor :inject_error
@@inject_one_error = false
cattr_accessor :inject_one_error
class << self
private
def perform_delivery_test(mail)
if inject_error or inject_one_error
ActionMailer::Base::inject_one_error = false
raise "Failed to send email" if raise_delivery_errors
else
deliveries << mail
end
end
end
}
Now, in my test controller, I can reference the ActionMailer::Base
class instead of the Notifier (though there''s no reason this is really
necessary), and the Notifier class is referenced in the controller
itself, but now has error injection.
If this is useful for anyone, I''ll have it up in the salted-login
project on RubyForge sometime later today or tomorrow (it''ll be in
version 1.0.5 or later).
Joe
On Apr 18, 2005, at 4:30 PM, Joseph Hosteny wrote:
> Hi all,
>
> I''m trying to use either a mock or an extension to ActionMailer
to
> effectively add an error injection mechanism for some unit tests.
> Currently, I have a config variable that I turn on and off in the unit
> test. If this flag is on, the ActionMailer model raises an exception.
> Obviously, this is a little ugly.
>
> What I''d like to effectively do is change ActionMailer to have
the
> following:
>
> module ActionMailer
> class Base
> @@inject_one_error = false
> cattr_accessor :inject_one_error
>
> class << self
> private
> def perform_delivery_test
> if inject_one_error
> Base::inject_one_error = false
> raise "Failed to send email" if raise_delivery_errors
> else
> deliveries << mail
> end
> end
> end
> end
> end
>
> The, in my unit test, I have something like:
>
> ActionMailer::base.inject_one_error = true
> post :action, params => { "blah "}
>
> The :action call Notifier::deliver_some_mail(), where Notifier is my
> application specific model derived from ActionMailer::Base. The
> :action has the exception handling code, so I just verify some stuff
> about the state of the controller after that.
>
> Now, I''ve tried redefining this method in ActionMailer::Base::self
via
> module_eval in my notifier.rb model file. But this doesn''t work
for
> testing when running rake, I believe because of load order for modules
> (but I haven''t figured out how to do it correctly yet).
>
> So, has anyone done something like this, or set up a mock object for
> testing? I''d really like to hook into ActionMailer::Base::self, or
the
> functional equivalent, so I only have to implement a small amount of
> code instead of mucking with my Notifier class.
>
> Thanks,
> Joe
>
> _______________________________________________
> Rails mailing list
> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>