ruby-on-rails - Rspec 如何创建一个方法到 "DRY"只有请求的一些参数?

标签 ruby-on-rails ruby testing rspec rspec-rails

我想测试我项目的一个创建方法,但是这个创建方法在我的表单中有 3 个步骤,我想测试所有这些步骤。要测试每个步骤,我需要发送一个创建请求及其各自的步骤参数。

问题是:我在每一步都重复了很多参数,我想知道如何将常用参数放在一个方法中然后调用它。

这是我的 rspec 文件

require 'rails_helper'

RSpec.describe Api::MenteeApplicationsController, type: :controller do
    describe "Api Mentee Application controller tests" do
        let(:edition) { create(:edition) }

        it 'should start create a Mentee Application, step 1' do
            edition
            post :create, application: {
                first_name: "Mentee", last_name: "Rspec", email: "mentee@email.com",
                gender: "female", country: "IN", program_country: "IN",
                time_zone: "5 - Mumbai", communicating_in_english: "true",
                send_to_mentor_confirmed: "true",
                time_availability: 3,
                previous_programming_experience: "false" },
                step: "1", steps: "3"

            expect(response).to have_http_status(200)
        end

        it 'should continue to create a Mentee Application, step 2' do
            post :create, application: {
                first_name: "Mentee", last_name: "Rspec", email: "mentee@email.com",
                gender: "female", country: "IN", program_country: "IN",
                time_zone: "5 - Mumbai", communicating_in_english: "true",
                send_to_mentor_confirmed: "true",
                time_availability: 3,
                motivation: "Motivation",
                background: "Background",
                team_work_experience: "Team Work Experience",
                previous_programming_experience: "false" },
                step: "2", steps: "3"

            expect(response).to have_http_status(200)
        end

        it 'should not create a Mentee Application in api format' do
            applications = MenteeApplication.count
            post :create, application: {
                first_name: "Mentee", last_name: "Rspec", email: "mentee@email.com",
                gender: "female", country: "IN", program_country: "IN",
                time_zone: "5 - Mumbai", communicating_in_english: "true",
                send_to_mentor_confirmed: "true",
                motivation: "Motivation",
                background: "Background",
                team_work_experience: "Team Work Experience",
                previous_programming_experience: "false", experience: "",
                operating_system: "mac_os",
                project_proposal: "Project Proposal",
                roadmap: "Roadmap",
                time_availability: 3,
                engagements: ["master_student", "part_time", "volunteer", "one_project"] },
            step: "3", steps: "3"

            expect(response).to have_http_status(:unprocessable_entity)
            expect(MenteeApplication.count).to be(0)
        end

        it 'should create a Mentee Application in api format (step 3)' do
            applications = MenteeApplication.count
            post :create, application: {
                first_name: "Mentee", last_name: "Rspec", email: "mentee@email.com",
                gender: "female", country: "IN", program_country: "IN",
                time_zone: "5 - Mumbai", communicating_in_english: "true",
                send_to_mentor_confirmed: "true",
                motivation: "Motivation",
                background: "Background",
                programming_language: "ruby",
                team_work_experience: "Team Work Experience",
                previous_programming_experience: "false", experience: "",
                operating_system: "mac_os",
                project_proposal: "Project Proposal",
                roadmap: "Roadmap",
                time_availability: 3,
                engagements: ["master_student", "part_time", "volunteer", "one_project"] },
            step: "3", steps: "3"

            expect(response).to have_http_status(200)
            expect(MenteeApplication.count).to be(applications+1)
            expect(flash[:notice]).to eq("Thank you for your application!")
        end

    end
end

如您所见,第 1 步中的参数在第 2 步和第 3 步中使用,所以我的想法是这样的:

def some_params
    params.require(:application).permit(first_name: "Mentee", last_name: "Rspec", email: "mentee@email.com",
            gender: "female", country: "IN", program_country: "IN",
            time_zone: "5 - Mumbai", communicating_in_english: "true",
            send_to_mentor_confirmed: "true",
            time_availability: 3,
            previous_programming_experience: "false")
end

但是没有用,我该怎么做呢?

最佳答案

let block 允许您定义在测试用例 (its) 中使用的变量。需要注意的一些关键点:

  • 它们是惰性求值的: block 中的代码在您调用变量之前不会运行(除非您使用 bang -- let! -- 这会强制求值)
  • 它们可能在内部 context 中被覆盖

前往 RSpec docs了解更多关于他们的信息。


您提供的代码可以像这样使用 let:

require 'rails_helper'

RSpec.describe Api::MenteeApplicationsController, type: :controller do
    describe "Api Mentee Application controller tests" do
        let(:edition) { create(:edition) }
        let(:first_step_params) do
          {
            first_name: 'Mentee',
            last_name: 'Rspec',
            #...
            previous_programming_experience: false,
          }
        end
        let(:second_step_params) do
          {
            motivation: "Motivation",
            background: "Background",
            team_work_experience: "Team Work Experience",
          }.merge(first_step_params)
        end
        let(:third_step_params) do
          {
            operating_system: "mac_os",
            project_proposal: "Project Proposal",
            roadmap: "Roadmap",
            time_availability: 3,
            engagements: ["master_student", "part_time", "volunteer", "one_project"],
          }.merge(third_step_params)
        end

        it 'should start create a Mentee Application, step 1' do
            edition                                                          

            post :create, application: first_step_params, step: "1", steps: "3"

            expect(response).to have_http_status(200)                        
        end                                                                  

        it 'should continue to create a Mentee Application, step 2' do       
            post :create, application: second_step_params, step: "2", steps: "3"

            expect(response).to have_http_status(200)                        
        end

        it 'should not create a Mentee Application in api format' do
            applications = MenteeApplication.count

            post :create, application: third_step_params, step: "3", steps: "3"

            expect(response).to have_http_status(:unprocessable_entity)
            expect(MenteeApplication.count).to be(0)
        end
    end
end

其他建议

1。不实现 Controller 规范

Controller 是用户界面和后台服务之间的薄软件层。他们的测试很难被视为集成(端到端)测试或单元测试。

我建议您改用功能规范。 (capybara 非常适合使用 RSpec 进行 Rails 测试)

blog post可能会对此提供更多见解。

2。不要在你的测试用例描述中使用 should

参见 betterspecs.org .

3。注意

中的最后一个尾随逗号
let(:application_params) do                                                      
  {                                                                  
    first_name: 'Mentee',                                            
    last_name: 'Rspec',                                              
    #...                          
    previous_programming_experience: false,
  }                                                                  
end

它阻止了 incidental changes .

4。使用 .rspec 文件

内容如

--require rails_helper

因此您不需要在每个规范文件顶部添加 require 'rails_helper'

5。使用 context

这也是来自 betterspecs.org 的指南。你可以做类似的事情

RSpec.describe Api::MenteeApplicationsController, type: :controller do
    describe "Api Mentee Application controller tests" do
        let(:edition) { create(:edition) }
        let(:application_params) do
          {
            #...
          }
        end
        let(:step) { 1 }

        it 'should start create a Mentee Application' do
            edition

            post :create, application: application_params, step: step, steps: "3"

            expect(response).to have_http_status(200)
        end

        context 'in second step' do
          let(:step) { 2 }

          it 'should continue to create a Mentee Application' do
              post :create, application: application_params, step: step, steps: "3"

              expect(response).to have_http_status(200)
          end
        end
    end
end

context 也可以方便地处理额外的参数:

RSpec.describe Api::MenteeApplicationsController, type: :controller do
  describe "Api Mentee Application controller tests" do
    let(:edition) { create(:edition) }
    let(:application_params) do
      common_params.merge(additional_params)
    end
    let(:commom_params) do
      {
        #...
      }
    end
    let(:additional_params) { {} }

    it 'creates an application' do
      post :create, application: application_params
    end

    context 'with API params' do
      let(:additional_params) do
        {
          #...
        }
      end

      it 'creates an application' do
        post :create, application: application_params
      end
    end
  end
end

请注意,post 方法调用在两种上下文中变得完全相同。这将允许重用它(在 before block 或什至另一个 let block 中)。

关于ruby-on-rails - Rspec 如何创建一个方法到 "DRY"只有请求的一些参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49278298/

相关文章:

ruby-on-rails - 使用 better_errors 作为调试器?

ruby-on-rails - Rails 和 CoffeeScript 在生产环境中编译错误

ruby - Sinatra 局部变量与实例变量

ruby - 尝试运行 delayed_job 时找不到命令

javascript - postman :如何在测试中迭代我的 JSON 文件?

sql - Postgres 查询包含某些内容的 JSON 数组

ruby-on-rails - "PG::UndefinedTable: ERROR: relation does not exist"具有正确的 Rails 命名和约定

ruby-on-rails - 我无法在 Arch Linux x64 中安装 therubyracer

ios - 在 cocoa 单元测试目标中运行测试之前运行脚本

unit-testing - 没有 Maven 和 JBoss AS 的 JSFUnit