Rails 5 Rspec使用ActionController :: Params接收

Car*_*ham 6 ruby rspec ruby-on-rails ruby-on-rails-5

我刚刚升级到Rails 5.在我的规格中,我有以下内容

expect(model).to receive(:update).with(foo: 'bar')

但是,由于params不再延伸,Hash但现在ActionController::Parameters规格正在失败,因为with()期待哈希,但事实上ActionController::Parameters

有没有更好的方法在Rspec中做同样的事情,比如不同的方法with_hash

我可以解决这个问题

expect(model).to receive(:update).with(hash_including(foo: 'bar'))

但这只是检查params是否包含该哈希,而不是检查完全匹配.

max*_*max 5

你可以这样做:

params = ActionController::Parameters.new(foo: 'bar')
expect(model).to receive(:update).with(params)
Run Code Online (Sandbox Code Playgroud)

然而它仍然闻起来 - 你应该测试应用程序的行为 - 而不是它如何完成它的工作.

expect {
  patch model_path(model), params: { foo: 'bar' }
  model.reload
}.to change(model, :foo).to('bar')
Run Code Online (Sandbox Code Playgroud)

这就是我测试控制器集成的方法:

require 'rails_helper'
RSpec.describe "Things", type: :request do
  describe "PATCH /things/:id" do

    let!(:thing) { create(:thing) }
    let(:action) do
      patch things_path(thing), params: { thing: attributes }
    end

    context "with invalid params" do
      let(:attributes) { { name: '' } }
      it "does not alter the thing" do
         expect do 
           action 
           thing.reload
         end.to_not change(thing, :name)
         expect(response).to have_status :bad_entity
      end
    end

    context "with valid params" do
      let(:attributes) { { name: 'Foo' } }
       it "updates the thing" do
         expect do 
           action 
           thing.reload
         end.to change(thing, :name).to('Foo')
         expect(response).to be_successful
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

触摸数据库中的规范继承不好吗?

不.当您测试控制器之类的东西时,最准确的测试方法是驱动整个堆栈.如果我们在这种情况下已经存根,@thing.update我们可能错过了例如数据库驱动程序引发错误,因为我们使用了错误的SQL语法.

如果您是在模型上测试范围,那么存储数据库的规范将为您提供很少甚至没有价值.

Stubbing可能会给你一个快速测试套件,由于紧密耦合而非常脆弱,并且可以让大量的虫子穿过裂缝.

  • 那时没有铁轨@ RustamA.Gasanov. (2认同)
  • 我同意不剔除模型。但是,如果我需要测试由控制器调用的(服务)对象,并且根据输入执行各种操作,则单独测试该对象要容易得多,并且在控制器中仅测试它是否通过了所有内容需要那个对象。功能规范通常应该测试所有内容是否也能很好地集成到基本场景中。 (2认同)

Ste*_*eve 5

我通过在spec / rails_helper.rb中创建来处理此问题

def strong_params(wimpy_params)
  ActionController::Parameters.new(wimpy_params).permit!
end
Run Code Online (Sandbox Code Playgroud)

然后在特定测试中,您可以说:

expect(model).to receive(:update).with(strong_params foo: 'bar')
Run Code Online (Sandbox Code Playgroud)

它与您已经在做的事情没有太大不同,但是这使得额外调用的尴尬必要性在语义上更加有意义。