如何在使用Rails Mailer参数化时如何最好地使用RSPEC模拟

发布于 2025-02-09 00:11:20 字数 1074 浏览 2 评论 0原文

我目前正在更改我们的栏杆邮件,以使用使用参数化的邮件器的较新方法,这使我们的代码基础与 rails指南,但更重要的是,它还允许在appsignal(例如appsignal)的日志和第三方应用程序中适当过滤参数。

IE。我正在将其更改

UserMailer.new_user_email(user).deliver_later

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

,但是我们有很多规格使用RSPEC模拟来确认使用适当的参数调用邮件器。通常,这些控制器实际上要求邮件器正确地花费电子邮件。

我们通常有类似的东西:

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

但是现在,随着邮件的参数化,我看不到使用RSPEC模拟的任何简单方法来验证正确的邮件方法是否使用正确的参数调用。有人对现在如何最好地测试有什么想法吗?期望的可读性可能是这里的最大因素,理想情况下,它是一行,没有多行嘲笑设置。

注意:我真的不想实际运行邮件器,我们有测试实际邮件器正在工作的邮件单元规格。

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.

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. 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. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

儭儭莪哋寶赑 2025-02-16 00:11:20

因此,对于将来出现这个问题的其他任何人来说。我最终在规格/支持目录中添加了一个辅助方法,

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

然后用类似的内容可以在类似的规范中调用

expect_mailer_call(UserMailer, :new_user_email, { to:'[email protected]', name: kind_of(String) })

,或者用于evelry_now,

expect_mailer_call(UserMailer, :new_user_email, { to:'[email protected]', name: kind_of(String) }, :deliver_now)

它可以适应我们的情况,但是您可能需要调整它并为此添加零件如果您需要配置曾经限制的电子邮件或其他内容。

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

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 protected]', name: kind_of(String) })

or for deliver_now

expect_mailer_call(UserMailer, :new_user_email, { to:'[email protected]', 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.

深居我梦 2025-02-16 00:11:20

当您有几个被链接的方法时,您可以使用receed_message_chain
但是有一个反抽奖 - 它不支持 两次的整个计数器的整个流利接口,

因此您必须在这里做一个技巧:

# 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

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文