blog.kotamiyake.me

為せば成る、為さねば成らぬ何事も

Railsでサービスを開発していると、バックグラウンドで処理を実行するジョブを実装することがあるかと思います。

そんなとき、いつもテストの書き方を忘れてしまうので、内容の理解と整理のために備忘録として記事を書こうと思います。

まずはそもそもどういったものをテストするべきかを整理してみたいともいます。

ジョブ自身は基本的に同期的に実行しているモデルまたはメール送信などの処理をバックグラウンドで非同期に実行することが多いと思います。

なので、ユニットテストでは基本的には正確に意図したジョブが呼び出されているか、ということさえ確認できればよいのではないかと思います。

もちろんこれはジョブ実行メソッドの中に余計な処理が書かれていないことが前提となります。

それでは簡単なサンプルと解説を書いていきたいと思います。

まずは config.active_job.queue_adapter を設定します。ここでは :test を指定していますが、ご自身の環境に合わせて設定してください。

Rails.application.configure do
  # snip...
  config.active_job.queue_adapter = :test
end

それではテストコードを書いていきたいと思います。モデル、ジョブ、テストの順番にコードを書いていきます。

class Thing < ApplicationRecord
  after_commit :do_something_job

  def do_something
    # Do something...
  end

  private

  def do_something_job
    ThingJob.perform_later(self)
  end
end
class ThingJob < ActiveJob::Base
  def perform(thing)
    thing.do_something
  end
end
require 'rails_helper'

RSpec.describe Thing, type: :model do
  include ActiveJob::TestHelper

  describe '#do_something_job' do
    it 'enqueues `ThingJob`' do
      expect {
        Thing.create!
      }.to have_enqueued_job(ThingJob)
    end
  end
end

普段からRailsを利用している開発者からしたらどうということのないコードかと思います。

処理の流れとしては、Thing の作成(または更新)処理が行われると、commit をフックとして do_something_job の中で ThingJob が実行されます。

ThingJob では Thing#do_something が実行されます。

最初に書いたとおり、ここではコールバックの実行とともに想定通りのジョブがキューに追加されるかどうか、という部分を確認しています。

ActiveJob::TestHelper は実際にはなくても動くのですが、モジュールの中でジョブの初期化処理をやってくれているので、特に問題がなければインクルードしておくと良いかと思います。

勝手に初期化して欲しくないということであれば、上記のヘルパーを参考にして初期化処理をかくとよいかと思います。

と、ここまで書いておいてアレなのですが、実はRSpecのドキュメントにその他の細かいマッチャーなどもしっかり記載されています。

さらに詳細な条件でテストをしたい場合には、RSpecのドキュメントを参考にしてみてください。

すべてのケースをテストでカバーできるということはあり得ないのですが、それでも基本的なケースをいくつか抑えておくだけで変更の際の安心感が変わってきます。

苦手意識を持たず、満遍なくテストを書くことができるようにしていきましょう。