RSpec忽略了控制器中的救援块

Rod*_*tro 5 rspec ruby-on-rails ruby-on-rails-4

我有一个Rails控制器,它对数据库进行运行状况检查,如下所示:

def health_check
  begin
    status = ActiveRecord::Base.connected? ? 'UP' : 'DOWN'
  rescue
    status = 'DOWN'
  end
  render text: status
end
Run Code Online (Sandbox Code Playgroud)

我正在尝试为此创建一个RSpec控制器规范,正响应和负响应的规范都起作用,但是当我尝试测试救援块时,RSpec似乎忽略了它:

RSpec.describe(HealthCheckController) do
  context 'When the check raises an exception' do
    before :each do
      allow(ActiveRecord::Base).to receive(:connected?).and_raise(OCIException) # Using Oracle
    end

    it 'should render text DOWN' do
      # First attempt
      get :health_check
      expect(response.body).to eq 'DOWN'

      # Second attempt
      expect { get :health_check }.to raise_error
      expect(response.body).to eq 'DOWN'
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我在it上面的块中(分别)使用了这两个代码尝试了规范。

首先,RSpec失败了:

 Failure/Error: get :health_check
     OCIException:
       OCIException
Run Code Online (Sandbox Code Playgroud)

第二,它也失败了,而是显示了更多“熟悉的”消息:

Failure/Error: expect(response.body).to eq 'DOWN'

       expected: "DOWN"
            got: ""

       (compared using ==)
Run Code Online (Sandbox Code Playgroud)

我还检查了响应返回的HTTP代码,它是200,因此响应本身很好,没有500错误。

就像RSpec只是绕过救援块并没有运行它一样。是什么原因造成的?我不在bypass_rescue任何地方使用RSpec方法,这也是一个新项目。

使用方法:

Rails 4.2.6
Rake 10.5.0
RSpec-core 3.3.2
RSpec-rails 3.3.3
Run Code Online (Sandbox Code Playgroud)

Ale*_*nko 0

rescue实际上,问题与控制器中的块无关。相反,它是由于您ActiveRecord::Base#connected?通过在before块中存根它来覆盖它而引起的。

调用render控制器会启动与数据库的连接。在该过程的某个地方ActiveRecord::Base#connected?被调用(实际上两次),但它没有返回它应该返回的内容,而是引发了您在设置中定义的异常。

在您的第一个示例中,异常是在您的预期之前引发的,因此失败消息中包含显式异常名称。

在您的第二个示例中,您的期望抑制了异常raise_error,因此 RSpec 能够继续进行下一个示例。由于render控制器中的调用从未运行(由于错误)而失败,因此,响应正文永远没有机会被填充。

ActiveRecord::Base#connected?作为在调用 时确实被调用的确认render,请尝试运行以下规范。你会看到它是绿色的,这意味着该方法在此过程中被调用了两次。您还可以尝试替换renderhead :ok并 会看到在这种情况下ActiveRecord::Base#connected?仅被调用一次。

RSpec.describe ApplicationController do
  controller do
    def index
      render json: ''
    end
  end

  specify 'test' do
    expect(ActiveRecord::Base).to receive(:connected?).twice
    get :index
  end
end
Run Code Online (Sandbox Code Playgroud)