使用 RSpec 进行测试时,如何在 Sidekiq worker 中正确捕获错误?

How can I trap errors correctly in a Sidekiq worker when testing with RSpec?

我有一个相对简单的工人,使用 Excon 从互联网上抓取一些东西。我正在努力成为一名优秀的测试人员,并使用 Webmock 强制对 Internet 交互进行存根,这样我实际上是在测试代码应该根据各种存根交互执行的操作。

我注意到 RSpec 没有捕获 worker 内部发生的故障。这可能是我的代码,也可能是错误,我不确定。

这是一个简单的 worker 示例(是的,我知道拯救异常很糟糕,接下来我会修复它):

  include Sidekiq::Worker
  sidekiq_options queue: 'fetch_article_content', retry: true, backtrace: true

  def perform(url)
    begin
      Excon.get(url)
    rescue Exception => e
      Rails.logger.warn("error: #{e}")
      nil
    end
  end
end

这是一个简化的 RSpec 测试:

      Sidekiq::Testing.inline!
      work = FetchArticleContentWorker.new
      work.perform("http://google.com")

启用 Webmock 后,这会导致 Excon 失败(见 test.log 文件):

error: Real HTTP connections are disabled. Unregistered request: ...

但是,RSpec 认为这很好用:

.

Finished in 0.44487 seconds (files took 5.35 seconds to load)
1 example, 0 failures

我不确定我做错了什么。我希望 Sidekiq perform 未能冒泡到 RSpec 作为失败,但事实并非如此。

谢谢!

我认为从 rspec 的 perspec 角度来看没有错误,因为它在 worker 内部 captured/handled。如果您删除了救援,我预计测试会失败,正如您所期望的那样。相反,您可以检查测试以查看是否执行 returns 非零值才能通过。有帮助吗?

为了 RSpec 看到异常,代码必须引发异常。

您可以重新提出现有异常:

def perform(url)
  begin
    Excon.get(url)
  rescue Exception => e
    Rails.logger.warn("error: #{e}")
    raise e
  end
end

您可以将现有异常包装在您自己的异常之一中:

class MyFancyException < StandardError; end

def perform(url)
  begin
    Excon.get(url)
  rescue Exception => e
    Rails.logger.warn("error: #{e}")
    raise MyFancyException.new(e)
  end
end

两者都有效。两者都需要一些类似于此的 RSpec:

describe Worker do
  subject(:worker) { described_class.new }

  describe "#perform" do
    subject(:perform) { worker.perform }

    let(:url) { "https://google.com" }

    it "raises exception" do
      expect { perform(url) }.to raise_error(MyFancyException)
    end
  end
end