如何修复 RSpec 中的任务测试?

How to fix a task test in RSpec?

我有一个名为 Jurisdiction 的 table 并创建了该任务来更新类型列:

namespace :populate_jurisdiction do
  desc "Populate column kind of jurisdiction model"
  task kind: :environment do
    Jurisdiction.all.each { |jurisdiction|
      case (jurisdiction.kind.nil? || jurisdiction.kind.blank?)
        when jurisdiction.name.parameterize == "federal"
        jurisdiction.kind = 1
        when jurisdiction.name.parameterize == "estadual"
        jurisdiction.kind = 2
        when jurisdiction.name.parameterize == "municipal"
          jurisdiction.kind = 3
        when jurisdiction.name.parameterize == "privado"
        jurisdiction.kind = 4
      end
      jurisdiction.save!
    }
  end
end

然后我创建了那个测试

require "spec_helper"

Rails.application.load_tasks

describe "populate_jurisdiction:kind" do
  context "when update kind column of jurisdiction" do
    let(:federal) { create(:jurisdiction, name: "Federal", kind: nil) }
    let(:state) { create(:jurisdiction, name: "Estadual", kind: nil) }
    let(:municipal) { create(:jurisdiction, name: "Municipal", kind: '') }
    let(:particular) { create(:jurisdiction, name: "Privado", kind: '') }

    it "when kind column is updated" do
      Rake::Task["populate_jurisdiction:kind"].invoke
      expect(federal.kind).to eq(1)
      expect(state.kind).to eq(2)
      expect(municipal.kind).to eq(3)
      expect(particular.kind).to eq(4)
    end
  end
end

当我 运行 在 rails 控制台中执行任务时它工作,但是当我 运行 测试时,我得到了这个错误

Failures:

  1) populate_jurisdiction:kind when update kind column of jurisdiction when kind column is updated
     Failure/Error: expect(federal.kind).to eq(1)
     
       expected: 1
            got: nil
     
       (compared using ==)

我做错了什么?我该如何修复这个测试?

当您调用 rake 任务时,没有管辖权,这就是您得到 nil 的原因。例如,federal 管辖权仅在您调用 federal.kind.

rake 任务后创建
require "spec_helper"

Rails.application.load_tasks

describe "populate_jurisdiction:kind" do
  context "when update kind column of jurisdiction" do
    let(:federal) { create(:jurisdiction, name: "Federal", kind: nil) }
    let(:state) { create(:jurisdiction, name: "Estadual", kind: nil) }
    let(:municipal) { create(:jurisdiction, name: "Municipal", kind: '') }
    let(:particular) { create(:jurisdiction, name: "Privado", kind: '') }

    it "when kind column is updated" do
      # NOTE: jurisdictions are not created until `let` blocks are called.
      federal
      state
      municipal
      particular      

      Rake::Task["populate_jurisdiction:kind"].invoke

      # NOTE: `let` return values are memoized, second call will just
      #        retrieve the value. You have to reload the models as well
      #        to get the updated values from the database.
      expect(federal.reload.kind).to eq(1)
      expect(state.reload.kind).to eq(2)
      expect(municipal.reload.kind).to eq(3)
      expect(particular.reload.kind).to eq(4)
    end
  end
end

https://relishapp.com/rspec/rspec-core/v/3-11/docs/helper-methods/let-and-let

您正在创建任何司法管辖区之前调用抽成任务。当你这样说时:

let(:federal) { create(:jurisdiction, name: "Federal", kind: nil) }

当您在测试中首次访问它时将创建 federal,然后在测试期间记住它。所以没有 federal 直到你的 rake 任务 运行s 之后。如果您使用 let! 而不是 let 并在任务 运行 之后重新加载管辖区,您会得到更好的结果。


顺便说一句,您的佣金任务并不像您认为的那样有效。 case有两种形式:

case expr
when value1
  ...
when value2
  ...
end

case
when expr1
  ...
when expr2
  ...
end

当您打算使用第二种形式时,您使用的是第一种形式,而您的代码却意外地起作用了。我怀疑当你 运行 时你所有的 kind 都是 nil,否则你最终会做:

case false
...
end

然后您将进入 jurisdiction.name.parameterize 测试失败的第一个分支。

您的任务应该更像:

Jurisdiction.all.reject { |j| j.kind.blank? }.each do |jurisdiction|
  case jurisdiction.name.parameterize
  when 'federal'
    jurisdiction.kind = 1
  when 'estadual'
    jurisdiction.kind = 2
  when 'municipal'
    jurisdiction.kind = 3
  when 'privado'
    jurisdiction.kind = 4
  end
  jurisdiction.save!
end

或:

Jurisdiction.all.reject { |j| j.kind.blank? }.each do |jurisdiction|
  jurisdiction.kind = case jurisdiction.name.parameterize
                      when 'federal' then 1
                      when 'estadual' then 2
                      when 'municipal' then 3
                      when 'privado' then 4
                      end
  jurisdiction.save!
end

如果 kind 是整数,则 kind.blank? 仅在 kind.nil? 时为真,以便可以将其推送到数据库中:

Jurisdiction.where(kind: nil).each do |jurisdiction|
  jurisdiction.kind = case jurisdiction.name.parameterize
                      when 'federal' then 1
                      when 'estadual' then 2
                      when 'municipal' then 3
                      when 'privado' then 4
                      end
  jurisdiction.save!
end

看起来 #parameterize 在这种情况下只会将 name 转换为小写,因此将所有逻辑推送到数据库中:

# This is an SQL CASE expression, not a Ruby one
Jurisdiction.where(kind: nil).update_all(%q(
  kind = case lower(name)
         when 'federal' then 1
         when 'estadual' then 2
         when 'municipal' then 3
         when 'privado' then 4
         end
))