使用 Rspec 模拟活动记录无效异常

mocking active record invalid exception with Rspec

我在 rspec 中模拟活动记录无效异常。

这是我遇到问题的方法。 image_processing_error 检查图像对象的错误。

def save_image(image)
  begin
    image.save!
      { message: I18n.t("messages.image_saved") , status: 200 }
    rescue ActiveRecord::RecordInvalid
      image_processing_error(image)
  end
end

private

def image_processing_error(image = nil)
  if image && image.errors.any? && image.errors.messages.any?
    { message: image.errors.messages.values[0][0] , status: 422 }
  else
    { message: I18n.t("errors.invalid_request"), status: 422 }
  end
end 

这是我的 rspec 同样的

# frozen_string_literal: true

require "rails_helper"

RSpec.describe ImagesService do
  describe ".save_image" do
    context "save image throws error" do
      let(:image) { double("image", { "errors": { "messages": { "name": ["is invalid", "must be implemented"]}}}) }

      before do
        allow(image).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
      end
      subject { described_class.save_image(image) }
      it "raised the error" do
        // I want to test the **ActiveRecord::RecordInvalid
        // I places NoMethodError to just pass the test
        expect { subject }.to raise_error NoMethodError
        expect { subject }.to raise_error ActiveRecord::RecordInvalid
      end
    end
  end
end

当我读取图像错误时出现以下错误。我必须让它正常工作的正确双精度值是多少。

Failures:

  1) ImagesService.save_image save image throws error raised the error
     Failure/Error: expect { subject }.to raise_error ActiveRecord::RecordInvalid
     
       expected ActiveRecord::RecordInvalid, got #<NoMethodError: undefined method `messages' for {:messages=>{:name=>["is invalid", "must be implemented"]}}:Hash> with backtrace:

在这种情况下,您在调用 subject 时没有得到异常的原因是它没有引发异常。由于您在 save_image 中设置了一个救援块,如果在其中抛出异常,将调用救援块并且不会将异常传播给调用者,而是 image_processing_error被调用。

所以在您的规范中,当您调用 subject 时,您不会得到异常,而是会从 image_processing_error 中得到解析错误,据我了解,这实际上是预期行为。

在这种情况下,您可以做的是测试从 subject 获得的结果是否与您在这种情况下收到的预期错误消息匹配,例如:

it "returns the error messages" do
    expect(response.body).to include("is invalid", "must be implemented")
end