我需要存根这个方法中的所有东西才能通过吗?

Do I need to stub EVERYTHING in this method in order to pass?

我通常是 mocha 的新手,我讨厌使用它 gem 但我需要使用它才能通过我正在构建的测试。给我带来问题的是我应该嘲笑什么以及我应该如何嘲笑它。为了说明我的观点,下面是我正在测试的方法示例:

 def statistics_of_last_24_hrs
    stats = ses.statistics.find_all { |s| s[:sent].between?(Time.now.utc - 24.hours, Time.now.utc) }
    sent_last_24_hrs = ses.quotas[:sent_last_24_hours].to_f
    no_of_bounces = stats.inject(0.0) { |a, e| a + e[:bounces] }
    no_of_complaints = stats.inject(0.0) { |a, e| a + e[:complaints] }
    bounce_rate = sent_last_24_hrs.zero? ? 0.0 : (no_of_bounces / sent_last_24_hrs) * 100
    complaint_rate = sent_last_24_hrs.zero? ? 0.0 : (no_of_complaints / sent_last_24_hrs) * 100
    fail(Reverification::SimpleEmailServiceLimitError, 'Bounce Rate exceeded 5%') if bounce_rate >= 5.0 
    fail(Reverification::SimpleEmailServiceLimitError, 'Complant Rate exceeded .1%')if complaint_rate >= 0.1 
  end

基本上这段代码所做的是从 Amazon api 调用中获取一些统计数据,然后计算它们以确定我的 bounce/complaint 速率是否超出了限制。上限分别为5%和0.1%。

基本上对于我的测试,我真正需要做的就是存根变量 bounce_ratecomplaint_rate 以测试是否抛出了正确的异常。

这就是我卡住的地方。这是我理想情况下编写的准系统测试:

it 'should raise SimpleEmailServieLimitError if bounce rate is above 5%' do
  assert_raise Reverification::SimpleEmailServiceLimitError do
     Reverification::Process.statistics_of_last_24_hrs
  end
end

我怎样才能存根 bounce_rate 然后存根 complaint_rate。我四处搜索了一下,得出的结论是没有办法存根变量。我也看了这个 link List of Mocha Methods这证实了我的发现。

有什么方法可以像这样编写测试:

 it 'should raise SimpleEmailServieLimitError if bounce rate is above 5%' do
  stubs(:bounce_rate).returns(true)
  assert_raise Reverification::SimpleEmailServiceLimitError do
     Reverification::Process.statistics_of_last_24_hrs
  end
end

或者我是否必须对该方法中的每个方法调用进行存根,以便测试看起来像这样:

it 'should raise SimpleEmailServieLimitError if bounce rate is above 5%' do
  sent_last_24_hrs = 20
  over_bounce_limit = MOCK::AWS::SimpleEmailService.over_bounce_limit
  AWS::SimpleEmailService.any_instance.stubs(:statistics).returns(stub(find_all: over_bounce_limit))
  AWS::SimpleEmailService.any_instance.stubs(:quotas).returns(stub(sent_last_24_hours: sent_last_24_hrs))
  etc. etc. etc...........
  assert_raise Reverification::SimpleEmailServiceLimitError do
     Reverification::Process.statistics_of_last_24_hrs
  end
end

有更简单的方法吗?

即使有一种存根局部变量的方法,该功能也会产生非常难以维护的测试,因为如果不更改测试就无法重构代码。

嵌套的存根也有设计味道 - 您的测试将了解太多的实现细节并且将变得无法维护。

对第三方代码存根也是如此,因为对第三方库的任何更改都将允许您的测试通过,而代码不起作用。

围绕 AWS SimpleEmailService - 网关创建您自己的包装器要好得多。您将实现它以具有非常狭窄的稳定接口,例如

class BounceStatistics
  def no_of_bounces
  def no_of_complaints
  def sent_last_24_hrs
end

由于这个接口是您自己的并且很稳定,您可以安全地存根它并为您的测试提供替代实现:

assert_raise Reverification::SimpleEmailServiceLimitError do
  Reverification::Process.statistics_of_last_24_hrs(
    stub(no_of_bounces: 2, no_of_complaints: 3, sent_last_24_hrs: 5))
end

或者您可以将其实现为

BounceStatistics.any_instance.stubs(:no_of_bounces).returns(2)
BounceStatistics.any_instance.stubs(:no_of_complaints).returns(3)
BounceStatistics.any_instance.stubs(:sent_last_24_hrs).returns(5)

assert_raise Reverification::SimpleEmailServiceLimitError do
  Reverification::Process.statistics_of_last_24_hrs
end

然而,显式传递依赖项可以让您拥有更易于维护的代码和更简单的测试。