简体   繁体   English

使用 rails mailer 参数化时如何最好地使用 rspec 模拟

[英]How to best use rspec mocks when using rails mailer parameterization

I'm currently changing our rails mailers to use the newer way of using the mailer that uses parameterization, which brings our code base inline with the rails guide , but more importantly it also allows the parameters to be filtered appropriately in the logs and 3rd party apps like AppSignal.我目前正在更改我们的 rails 邮件程序以使用使用参数化的邮件程序的更新方式,这使我们的代码库与rails guide内联,但更重要的是它还允许在日志和第 3 方中适当过滤参数AppSignal 等应用程序。

ie. IE。 I'm changing this我正在改变这个

UserMailer.new_user_email(user).deliver_later

to

UserMailer.with(user: user).new_user_email.deliver_later

But we have a quite a few specs that use Rspec Mocks to confirm that a mailer was called with the appropriate params.但是我们有很多规范使用 Rspec Mocks 来确认使用适当的参数调用了邮件程序。 Generally these test that a controller actually asked the mailer to spend the email correctly.通常,这些测试控制器实际上要求邮件发送者正确使用电子邮件。

We generally have something like:我们一般有这样的:

        expect(UserMailer).to receive(:new_user_email)
                                .with(user)
                                .and_return(OpenStruct.new(deliver_later: true))
                                .once

But now with the parameterization of the mailer, I don't see any easy way to use rspec mocks to verify that the correct mailer method was called with the correct params.但是现在有了邮件程序的参数化,我看不到任何简单的方法来使用 rspec 模拟来验证是否使用正确的参数调用了正确的邮件程序方法。 Does anyone have any ideas on how best to test this now?有人对现在如何最好地进行测试有任何想法吗? Readability of the expectation is probably the biggest factor here, ideally it is one line without multiple lines of mocking setup.期望的可读性可能是这里最大的因素,理想情况下它是一行没有多行模拟设置。

Note: that I don't really want to actually run the mailer, we have mailer unit specs that test the actual mailer is working.注意:我真的不想实际运行邮件程序,我们有邮件程序单元规格来测试实际邮件程序是否正常工作。

When you have couple of methods which are chained you can use receive_message_chain But there is one backdraw - it doesn't support the whole fluent interface of counters like once twice当您有几个链接的方法时,您可以使用receive_message_chain但是有一个回撤-它不支持计数器的整个流畅界面,例如once twice

So you have to do one trick here:所以你必须在这里做一个技巧:

# set counter manually
counter = 0

expect(UserMailer).to receive_message_chain(
  :with, :new_user_email
).with(user: user).with(no_args).and_return(OpenStruct.new(deliver_later: true)) do
  counter += 1
end

# Very important: Here must be call of your method which triggers `UserMailer` mailer. For example
UserNotifier.notify_user(user)

expect(counter).to eq(1)
# class for example
class UserNotifier
  def self.notify_user(user)
    UserMailer.with(user: user).new_user_email.deliver_later
  end
end

So for anyone else that hits this problem in the future.因此,对于将来遇到此问题的其他任何人。 I ended up adding a helper method in the specs/support directory with something like this我最终在 specs/support 目录中添加了一个辅助方法,如下所示

def expect_mailer_call(mailer, action, params, delivery_method = :deliver_later)
  mailer_double = instance_double(mailer)
  message_delivery_double = instance_double(ActionMailer::MessageDelivery)
  expect(mailer).to receive(:with).with(params).and_return(mailer_double)
  expect(mailer_double).to receive(action).with(no_args).and_return(message_delivery_double)
  expect(message_delivery_double).to receive(delivery_method).once
end

Which can then be called in a spec like this然后可以在这样的规范中调用

expect_mailer_call(UserMailer, :new_user_email, { to:'email@email.com', name: kind_of(String) })

or for deliver_now或为 Deliver_now

expect_mailer_call(UserMailer, :new_user_email, { to:'email@email.com', name: kind_of(String) }, :deliver_now)

It works good enough for our situation, but you might need to adapt it and add a part for the amount of emails or something if you need to configure the once restriction.它适用于我们的情况,但如果您需要配置一次限制,您可能需要对其进行调整并添加部分电子邮件或其他内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM