ruby-on-rails 不同用户上下文的DRY请求规范

doinxwow  于 5个月前  发布在  Ruby
关注(0)|答案(2)|浏览(71)

我正在开发一个API应用程序,在这个例子中,它有两种基本的用户类型,adminuser
对于这个例子,资源将是Widget。管理员可以完全访问控制器中的小部件,而用户没有访问权限。现在,我在编写请求规范时重复了很多次。
EG

require 'rails_helper'

RSpec.describe '/widgets', type: :request do
  context 'with an admin user' do
    let(:user) { create(:user, is_admin: true) }
    let(:valid_attributes) { attributes_for(:widget) }
    let(:invalid_attributes) { attributes_for(:widget, name: nil) }
    let(:valid_headers) { Devise::JWT::TestHelpers.auth_headers({}, user) }

    describe 'GET /widgets' do
      it 'renders a successful response' do
        create(:widget)
        get widgets_url, headers: valid_headers, as: :json
        expect(response).to be_successful
      end
    end
  end

  context 'with a standard user' do
    let(:user) { create(:user) }
    let(:valid_attributes) { attributes_for(:widget) }
    let(:invalid_attributes) { attributes_for(:widget, name: nil) }
    let(:valid_headers) { Devise::JWT::TestHelpers.auth_headers({}, user) }

    describe 'GET /widgets' do
      it 'renders an unauthorized response' do
        create(:widget)
        get widgets_url, headers: valid_headers, as: :json
        expect(response).to have_http_status(403)
      end
    end
  end
end

字符串
现在想象一下,这一切都是在API的整个CRUD上完成的,我的请求规范长达100行,有很多复制粘贴,它们很难阅读,也很难管理。
大多数样板都是一样的,我只是想实现不同的用户上下文来验证我的策略是否生效。
在一个完美的世界里,我可以定义一次describecontext块,然后根据用户上下文做出不同的期望。
有什么建议去哪里找?

dsf9zpds

dsf9zpds1#

你可以调出大部分的let,因为它们会被延迟计算。例如:

require 'rails_helper'

RSpec.describe '/widgets', type: :request do
  let(:valid_attributes) { attributes_for(:widget) }
  let(:invalid_attributes) { attributes_for(:widget, name: nil) }
  let(:valid_headers) { Devise::JWT::TestHelpers.auth_headers({}, user) }

  context 'with an admin user' do
    let(:user) { create(:user, is_admin: true) }

    describe 'GET /widgets' do
      it 'renders a successful response' do
        create(:widget)
        get widgets_url, headers: valid_headers, as: :json
        expect(response).to be_successful
      end
    end
  end

  context 'with a standard user' do
    let(:user) { create(:user) }

    describe 'GET /widgets' do
      it 'renders an unauthorized response' do
        create(:widget)
        get widgets_url, headers: valid_headers, as: :json
        expect(response).to have_http_status(403)
      end
    end
  end
end

字符串
我会进一步反对“DRYing”。特别是测试应该详细说明他们所确保的功能。

ffdz8vbo

ffdz8vbo2#

您希望使用shared examples,甚至可能将其推到一个单独的文件中,
它将是这样的(注意,我还覆盖了subject来发出请求并返回request,这样您就可以使用is_expected.速记语法-如果您喜欢使用较长的expect(response).语法,则不需要这样做)

describe '/widgets', type: :request do
  let(:user_params) {{}}
  let(:user) { create(:user, user_params) }
  let(:valid_attributes) { attributes_for(:widget) }
  let(:invalid_attributes) { attributes_for(:widget, name: nil) }
  let(:valid_headers) { Devise::JWT::TestHelpers.auth_headers({}, user) }

  let(:params) { {} }
  let(:headers) { valid_headers }

  subject do
    process method, url, params: params, headers: headers, as: :json
    response
  end

  shared_examples "successful response" do
    it { is_expected.to have_http_status :ok }
  end

  shared_examples "unauthorized response" do
    it { is_expected.to have_http_status :forbidden }
  end

  describe "GET /widgets" do
    let(:method) { :get }
    let(:url) { "/widgets" }

    before { create(:widget) }

    context 'with an admin user' do
      let(:user_params) { { is_admin: true } }

      it_behaves_like "successful response"
    end

    context 'with a standard user' do
      it_behaves_like "unauthorized response"
    end
  end
end

字符串

相关问题