Rakeタスクのテストをする方法

実装したいこと

前回の記事で実装したrakeタスクの内容をRSpecでテストしたい。
備忘録として記事に残してます。

前提

RSpecFactoryBotは既に設定されているものとして記述してます。

実装

1. specディレクトリ配下にrake_helper.rbを作成し、設定を記述する。

require 'rails_helper'
require 'rake'

RSpec.configure do |config|
  config.before(:suite) do
    Rails.application.load_tasks # Load all the tasks just as Rails does (`load 'Rakefile'` is another simple way)
  end
 
  config.before(:each) do
    Rake.application.tasks.each(&:reenable) # Remove persistency between examples
  end
end

before(:suite):テスト実行時、ただ一度だけブロック内の処理を実行します。
Rails.application.load_tasks:lib/tasks配下のすべての.rakeファイルを読み込んでいる。
before(:each):各テストケースの前にブロック内の処理を都度実行します。
Rake.applicationRake::Applicationインスタンスを生成しており、読み込むファイルの拡張子やファイル名を定義している。 また、読み込む際のクラスも指定している。
reenableインスタンスを再度実行できるメソッド。Rakeタスクのテストを実行する場合、各テストケース間の結合性は邪魔になるので、各Rakeタスクを実行した履歴を消去した上で、再度利用できるようにしている。

2. specディレクトリ配下にrake_helper.rbを作成し、設定を記述する。

テストの内容は前回の記事にも記載したように、「「公開待ち」の記事に対して、公開日時が過去になっているものがあれば、状態を「公開」に変更する」タスクを想定してある。

FactoryBot.define do
  factory :article do
    sequence(:title) { |n| "title-#{n}" }
    sequence(:slug) { |n| "slug-#{n}" }
    state { :draft }
  end
end
require 'rake_helper'
 
 describe 'article_state:update_article_state' do
   subject(:task) { Rake.application['article_state:update_article_state'] }
   before do
     create(:article, state: :publish_wait, published_at: Time.current - 1.day)
     create(:article, state: :publish_wait, published_at: Time.current + 1.day)
     create(:article, state: :draft)
   end

   it 'update_article_state' do
     expect { task.invoke }.to change { Article.published.size }.from(0).to(1)
   end
 end

invokeメソッドでRakeタスクを実行してある。他にはexecuteメソッドでも実行できる。

参考記事

RailsでRakeタスクをシンプルかつ効果的にテストする手法 - Qiita

https://kei-p3.hatenablog.com/entry/2016/08/11/232113