ActiveRecord依存のModuleをrspecでテストする


Ruby on Railsにてモデルの機能を拡張する方法は、モジュールをインクルードするのが一般的です。インクルードするモジュールがActiveRecordに依存しない内容であれば、単体テストを書くことは難しくありません。しかし、ActiveRecordに依存している場合はちょっと面倒です。なぜなら、インクルードする側のモデルに対応するテーブルが必要になるからです。今回は、そんな血ヘドを吐くような困難に打ち勝つ方法をご紹介します。

環境

  • Ruby on Rails 4.0.0
  • rspec-rails 2.14.0

サンプルモデル・モジュール

まずは、インクルードする側のArticleモデルです。

タイトル(title)・コンテント(content)・更新回数(updated_count)を持つモデルです。このモデルが UpdatedCountableモジュールをインクルードしています。

そして、こちらが UpdatedCountableモジュールです。

このモジュールをインクルードすると、自動的に before_saveコールバックにて updated_count属性がインクリメントされるという仕様になっています。トリガー的なモジュールというわけです。

それでは、この機能をrspecにてテストしましょう。(本当はテストが先なんですが!)

Articleモデルのspec

さっそく、spec/models/article_spec.rbに次のようなテストを書いてみました。

specを実行してみると・・・・・・見事に成功ですね! しかし、両手放しで喜んではいけません。もちろん、このままでも悪くはないのですが、少なくとも以下の点において非常に気持ちが悪いです。

  1. UpdatedCountableモジュールの仕様なのに、なんでArticleモデルのspecでテストしているんだ!
  2. 複数のモデルにインクルードされている場合、全部のモデルに同じspecを書くのか? 書かないのなら、どのモデルに書いたか忘れちゃいそう・・・
  3. 今後Articleモデルのテストコードが増えたときに、余計なコードがあると可読性が落ちる

といわけで、このテストをUpdatedCountableモジュール用に切り出してみましょう。

UpdatedCountableのspec

spec/models/concerns/updated_countable_spec.rbというファイルを作成し、そこにspecを書きます。

ポイントは before :all / after :all でダミーのテーブルを生成/破棄していることです。このテーブルが無いとArクラスはActiveRecordとして動いてくれません。specを実行してみると・・・・・・・・・成功です! う〜む、感慨深い。

しかし、まだちょっと気持ちが悪いですね。このままだと、この手のモジュールのspecを書く度に、テーブル生成・破棄の処理を書かなくてはいけません。明らかにリファクタリングの臭いを発するコードです。

こういったコードはspec_helperに持って行って、共通化してしましましょう。spec/spec_helper.rbの末尾に以下のコードを追加します。

呼び出す側の updated_countable_spec.rbも修正します。

非常にすっきりしました。再度specを実行すると・・・・・・・・・やっぱり成功! 見渡すかぎりの緑色。

これで、今後いくらモジュールが増えても怖くありません! なんだか、必要以上にモジュールを作ってしまいそうです。

関連する記事


ActiveRecord依存のModuleをrspecでテストする”に関する3件のコメント

  1. 趙自然

    I got this very strange question.
    Should it be
    Updatedcountable <-- lowercase 'c' in countable
    instead of
    UpdatedCountable
    ?

    1. itmammoth

      記事の著者

      I'm sorry to be not good at writing English, so it can be a strange module name for you.
      You can choose more appropriate name as you think.
      but how come you think using lowercase is better...?

      1. 趙自然

        Oh, I'm terribly sorry.
        I read it one more time.
        It is definitely my mistake.
        Your file name is app/models/concerns/updated_countable.rb (with the char _ that should work perfectly.

コメントは受け付けていません。