Rails Rspec 允许在一行中调用多个方法

Rails Rspec allow multiple method call in one line

desc 'Remove credential state users who no longer request for confirm otp within 10 minutes'
 task failed_user_cleaner: :environment do
 puts "Daily UserRecord Cleaning CronJob started - #{Time.now}"

 @user = User.with_state("credentials").with_last_otp_at(Time.now - 10.minutes)
 Users::Delete.new(@user).destroy_all

 puts "Daily UserRecord Cleaning CronJob ended - #{Time.now}"
end

以上是裁剪作业 rake 文件代码。

那我试了很多次,发现了很多次。 但是我找不到为上述工作编写单元测试用例的方法。

帮我正确写测试用例

这是我的规格代码

require 'rails_helper'

describe 'users rake tasks' do
  before do
    Rake.application.rake_require 'tasks/users'
    Rake::Task.define_task(:environment)
  end

  context 'when remove credential state users who no longer request for confirm otp within 10 minutes' do
    let(:user) { create(:user, last_otp_at: Time.now - 11.minutes, state: "credentials") }
    let (:run_users_rake_task) do
      Rake.application.invoke_task 'users:failed_user_cleaner'
    end

    it 'calls right service method' do
      @users = Users::Delete.new([user])
      expect(@users).to receive(:destroy_all)

      run_users_rake_task
    end
  end
end

这是错误日志

失败:

  1) users rake tasks when remove credential state users who no longer request for confirm otp within 10 minutes calls right service method
 Failure/Error: expect(@users).to receive(:destroy_all)
 
   (#<Users::Delete:0x0000556dfcca3a40 @user=[#<User id: 181, uuid: nil, phone: "+66969597538", otp_secret: nil, last_otp_at: "2021-09-30 09:32:24.961548000 +0700", created_at: "2021-09-30 09:43:24.973818000 +0700", updated_at: "2021-09-30 09:43:24.973818000 +0700", email: nil, avatar: "https://dummyimage.com/300x300/f04720/153572.png?t...", refresh_token: "eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MzI5Njk4MDQsImV4c...", first_name_en: "Jenise", first_name_th: "Damion", last_name_en: "McCullough", last_name_th: "Beatty", nationality: "TH", thai_national_id: nil, thai_laser_code: nil, company_id: 200, role: nil, state: "credentials", date_of_birth: "2020-10-30 00:00:00.000000000 +0700", deleted_at: nil, password_digest: "a$jfR9X9ci06602tlAyLOoRewTK1lZ12vJ2cZ9Dc2ov4F...", username: "zreejme238", shopname: nil, access_token: nil, locked_at: nil, login_attempts: 0, locale: "th", scorm_completed: false>]>).destroy_all(*(any args))
       expected: 1 time with any arguments
       received: 0 times with any arguments
 # ./spec/tasks/users_spec.rb:19:in `block (3 levels) in <top (required)>'

当 运行 此测试时,您正在创建 Users::Delete 的两个实例,一个在测试中,一个在任务中。由于未使用测试中的实例,因此期望它接收消息是不正确的。

Rspec 有一个预期,expect_any_instance_of,这将解决这个问题,但是考虑阅读整页,因为它可以创建脆弱或不稳定的测试。如果您想使用此方法,您的测试将类似于:

it 'calls right service method' do
  expect_any_instance_of(Users::Delete).to receive(:destroy_all)

  run_users_rake_task
end

就我个人而言,我会检查预期的用户是否已被删除,例如:

it 'removes the user' do
  expect { run_users_rake_task }.to change { User.exists?(id: @user.id) }.to(false)
end

除非您想使用 any_instance_of(这是一种代码味道),否则您需要对 Users::Delete 方法进行存根处理,使其 returns 成为双精度值并将期望值放在双精度值上:

require 'rails_helper'

describe 'users rake tasks' do
  before do
    Rake.application.rake_require 'tasks/users'
    Rake::Task.define_task(:environment)
  end

  context 'when remove credential state users who no longer request for confirm otp within 10 minutes' do
    let(:user) { create(:user, last_otp_at: Time.now - 11.minutes, state: "credentials") }
    let(:run_users_rake_task) do
      Rake.application.invoke_task 'users:failed_user_cleaner'
    end

    let(:double) do
       instance_double('Users::Delete') 
    end

    before do
      allow(Users::Delete).to receive(:new).and_return(double)
    end

    it 'calls right service method' do
      expect(double).to receive(:destroy_all)
      run_users_rake_task
    end
  end
end

然而,这实际上只是告诉我们服务对象的 API 很笨重,您应该编写一个 class 方法来实例化和执行:

module Users
  class Delete
    # ...
    def self.destroy_all(users)
      new(users).destroy_all
    end
  end
end
desc 'Remove credential state users who no longer request for confirm otp within 10 minutes'
 #...

 Users::Delete.destroy_all(@user)

 # ...
end
require 'rails_helper'

describe 'users rake tasks' do
  # ...
  context 'when remove credential state users who no longer request for confirm otp within 10 minutes' do
    # ...
    it 'calls right service method' do
      expect(Users::Delete).to receive(:destroy_all)
      run_users_rake_task
    end
  end
end