首页 > 解决方案 > RSpec:如何进行一个 shared_example 测试来测试许多不同的控制器 PATCH 请求,这些请求都更新不同的属性?

问题描述

我有各种控制器,并且我对每个控制器都进行了测试,以测试它们的更新操作。测试具有完全相同的结构:它测试补丁请求是否会更新和更改对象。这些测试之间的唯一区别是测试检查哪些属性以查看其更改断言。这些属性是控制器独有的。

class CarsController 

def update
   # update attribute
   ...
end

end

class DogsController 

def update
   # update attribute
   ...
end

end

我的测试(更多的两个):

CarsSpec 
describe "PATCH" do
  it "should update the car" do
    expect do 
      patch :update, id: object.id, data: {make: "honda"}
    end.to change {object.reload.make}
  end
end

DogSpec 
describe "PATCH" do
  it "should update the dog" do
    expect do 
      patch :update, id: object.id, data: {breed: "husky"}
    end.to change {object.reload.breed}
  end
end

正如你所看到的,它们自然是完全相同的测试结构,为了干燥,我想将它们提取到一个 shared_example 中以便干燥。我们的想法是拥有更多这些控制器,但只是实际测试,并且这些控制器只是通过哪个字段进行更新。它会涉及到类似的东西

shared_example "update" do
  it "updates the object" do
    expect do 
      patch :update, id.object.id, data: { customField: "new value" }
    end.to change { object.reload.customField }
  end
end

在这种情况下,customField 可以是品种或制造,并且测试会知道更新这些字段,因此它是通用的并且可以应用于许多这些控制器。我怎样才能做到这一点或类似的东西?

标签: ruby-on-railsrubymodel-view-controllerrspec

解决方案


shared_example的块接受参数:

shared_example "update" do |custom_field|
  it "updates the object (field: #{custom_field})" do
    expect do 
      patch :update, id.object.id, data: { custom_field => "new value" }
    end.to change { object.reload.public_send(custom_field) }
  end
end

并将其称为

include_examples 'update', :make
include_examples 'update', :breed

推荐阅读