Ruby on Rails - 这是消除 RSpec 中重复代码的好方法吗?

Ruby on Rails - Is this a good way to eliminate duplicate code in RSpec?

我写这段代码是为了测试控制器更新功能。 写了一个消除重复代码的方法。 这是一种明确的方式吗?

users_controller_spec.rb

context 'Update failed' do
  def render_edit
    user.reload
    expect(response.status).to eq(200)
  end
  it 'Name is nil' do
    put :update, params: { id: user.id, user: { name: '' } }
    render_edit
  end
  it 'Email is exist' do
    create(:user, email: 'user@gmail.com')
    put :update, params: { id: user.id, user: { email: 'user@gmail.com' } }
    render_edit
  end
  it 'Email is nil' do
    put :update, params: { id: user.id, user: { email: '' } }
    render_edit
  end
  it 'Password must be at least 8 characters' do
    put :update, params: { id: user.id, user: { password: '1234567', password_confirmation: '1234567' } }
    render_edit
  end
  it 'Passwords do not match' do
    put :update, params: { id: user.id, user: { password: '1234567890', password_confirmation: '123456789' } }
    render_edit
  end
end

我正在考虑使用 after(:each)。但它在逻辑上看起来有点连线。 或者用循环替换params.

有什么建议吗?

您可以按照评论中的建议使用共享示例,但还有一种更简单的方法。

context 'Update failed' do
  before do
    put :update, params: params
    user.reload # I'm not sure why you need this
  end

  subject { response } 

  context 'Name is nil' do
    let(:params} { {id: user.id, user: { name: '' }} }
    it { is_expected.to be_success }
  end

  context 'Email exists' do
    let(:params) { { id: user.id, user: { email: 'user@gmail.com' } }
    let(:user) { create(:user, email: 'user@gmail.com') }
    it { is_expected.to be_success }
  end
  # and so on
end

我使用的主要符文是 - 使每个上下文中的变化一目了然。因此,与其重新定义 put ...,不如将其提取为 let 并根据上下文定义它。

be_success 是 rspec 魔术的一部分,无论您在哪里使用 be_something 匹配器,它都会尝试使用 something? 方法并检查它是否为真,即

expect(foo).to be_empty? == expect(foo.empty?).to eq(true)

如果你不想这样做

subject { response.status }
# and later
is_expected.to eq 200 

is_expected.to 只是 shorthand 对于 expect(subject).to