Rails 5 Rspec使用ActionController :: Params接收

时间:2016-09-26 12:33:03

标签: ruby-on-rails ruby rspec 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是否包含该哈希值,而不是检查完全匹配。

3 个答案:

答案 0 :(得分:5)

你可以这样做:

params = ActionController::Parameters.new(foo: 'bar')
expect(model).to receive(:update).with(params)

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

expect {
  patch model_path(model), params: { foo: 'bar' }
  model.reload
}.to change(model, :foo).to('bar')

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

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

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

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

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

Stubbing可以为您提供一个快速测试套件,由于紧密耦合而非常脆弱,并且可以让大量的虫子穿过裂缝。

答案 1 :(得分:2)

我通过在spec / rails_helper.rb

中创建来处理此问题
def strong_params(wimpy_params)
  ActionController::Parameters.new(wimpy_params).permit!
end

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

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

它与你已经做过的事情没什么不同,但它使这个额外调用的尴尬必要性在语义上更有意义。

答案 2 :(得分:1)

@max对于如何完全避免这种情况提出了很好的建议,我同意他们从哈希转而不鼓励使用哈希值互换。

但是,如果您仍然想要使用它们,作为更复杂情况的简单黑客(例如,如果while(qr.next()){ salesTable = qr.get(tablenum(SalesTable)); } 使用expect),您可以尝试使用以下内容:

a_hash_including