当使用 mandril-api 时,Rails Action Mailer被绕过,因此无法做到这样的事情
it 'sends an email' do
expect { subject.send_instructions }
.to change { ActionMailer::Base.deliveries.count }.by(1)
end
我正在尝试使用object_double来测试我的邮件程序。我试图测试的是究竟是什么参数发送到API(通过选项哈希)。
到目前为止,我在这里有Mandrill代码
MANDRILL.messages.send_template( options[:template], [], message) unless Rails.env.staging?
MANDRILL只是API的连接,详见下文。
describe 'verify content' do
it 'uses the correct template' do
api = object_double(Mandrill::API.new(ENV['MANDRILL_KEY']).messages)
allow(api).to receive(:send_template)
PostNotificationMailer.format_options(participant, post)
expect(api).to have_received(:send_template)
#expect(options[:template]).to eq('crowdai_standard_template')
end
end
我希望能够在这里检查传递给Mandrill API的所有参数。我可以模拟消息方法,但不能模拟 messages.send_template
1) PostNotificationMailer verify content uses the correct template
Failure/Error: expect(api).to have_received(:send_template)
(ObjectDouble(#<Mandrill::Messages:0x007f8debd4f348 @master=#<Mandrill::API:0x007f8debd4faf0 @host="https://mandrillapp.com", @path="/api/1.0/", @session=#<Excon::Connection:7f8debd4f758 @data={:chunk_size=>1048576, :ciphers=>"HIGH:!SSLv2:!aNULL:!eNULL:!3DES", :connect_timeout=>60, :debug_request=>false, :debug_response=>false, :headers=>{"User-Agent"=>"excon/0.51.0"}, :idempotent=>false, :instrumentor_name=>"excon", :middlewares=>[Excon::Middleware::Hijack, Excon::Middleware::ResponseParser, Excon::Middleware::Expects, Excon::Middleware::Idempotent, Excon::Middleware::Instrumentor, Excon::Middleware::Mock], :mock=>false, :nonblock=>true, :omit_default_port=>false, :persistent=>false, :read_timeout=>60, :retry_limit=>4, :ssl_verify_peer=>true, :ssl_uri_schemes=>["https"], :stubs=>:global, :tcp_nodelay=>false, :thread_safe_sockets=>true, :uri_parser=>URI, :versions=>"excon/0.51.0 (x86_64-darwin15) ruby/2.3.1", :write_timeout=>60, :host=>"mandrillapp.com", :hostname=>"mandrillapp.com", :path=>"", :port=>443, :query=>nil, :scheme=>"https"} @socket_key="https://mandrillapp.com:443">, @debug=false, @apikey="redacted">>) (anonymous)).send_template(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
# ./spec/mailers/post_notification_mailer_spec.rb:14:in `block (3 levels) in <top (required)>'
**编辑**
有一个gem MandrillMailer解决了针对Mandril API进行测试的问题,但是它的构建已经破坏,它似乎也在内部重建了API。
How do I test mandrill api with rspec
我找不到有关如何使用object_double的任何教程或明确示例。
答案 0 :(得分:1)
您是否考虑过使用VCR gem(https://github.com/vcr/vcr)来记录API调用到mandrill的响应?记录请求后,您可以在响应中声明值以验证预期数据是否已通过。
答案 1 :(得分:1)
尽管我从您的代码中可以看出,PostNotificationMailer.format_options(participant, post)
无法知道其代码应该将send_template
方法发送到您的double而不是预定义的MANDRILL.messages
宾语。如果您在测试中调用Mandrill::API.new(ENV['MANDRILL_KEY'])
,即使您使用完全相同的代码定义MANDRILL
,也会返回与MANDRILL
完全不同的对象。因此,当邮件程序将方法发送到MANDRILL.messages
时,您的双重内容就会被遗忘。
不幸的是,即使您的测试被重写为基于MANDRILL.messages
的双倍,它仍然不会与邮件中的内容相同,因为邮件程序正在调用真实 MANDRILL.messages
而不是你的双倍。我理解它的方式,对于大多数双打,你仍然必须使用依赖注入。也就是说,您的邮件程序必须进行设置,以便您可以设置一个参数,即&#34;执行邮件的对象,&#34;类似的事情(我正在做这件事)PostNotificationMailer.set_api(some_object)
。在制作中,它将是PostNotificationMailer.set_api(MANDRILL)
,而在您的测试中,它将是PostNotificationMailer.set_api(api)
。可能这比它的价值更麻烦。
这似乎得到object_double documentation的证实,其中测试包括:
user = object_double(User.new, :save => true)
expect(save_user(user)).to eq("saved!")
如您所见,user
对象作为参数传递给我们尝试测试的方法,以便在double而不是其他对象上调用方法。
RSpec确实具有在常量上使用对象双精度的有趣能力,因此您不必使用依赖注入。但是,基于the relevant documentation,看起来您必须将对象名称作为字符串(而不是实际的对象引用)传递,然后您必须在双精度上调用as_stubbed_const
:
logger = object_double("MyApp::LOGGER", :info => nil).as_stubbed_const
Email.send_to('hello@foo.com')
expect(logger).to have_received(:info).with("Sent to hello@foo.com")
因此,如果您的应用程序为API的messages
对象定义了一个常量,然后将其名称作为字符串传递并调用as_stubbed_const
,那么它可能会起作用。我还没有尝试过像这样使用RSpec的双打,所以我无法肯定地说。