【Rails】Railsのモデルテストとシステムテストを書いてみる(test-unit)

先日フィヨルドブートキャンプでテスト技法について学習したのでブログにまとめます。 今回のプラクティスでRailsの課題用に作成されたappにモデルテスト(単体テスト)とシステムテスト(結合テスト)を書く課題があったので学習して学んだ点を書いていきます。


まず、テストで使うtest-unitですが、これはruby標準のテスティングフレームワークで、minitestをベースにしたものです。

単体テスト

どのような単位でテストを行うかはプログラミング言語の種類や開発者、プロジェクトの方針によっても異なります。ただ、多くの場合はクラスやメソッド、関数など、言語仕様上ほかのプログラムから一つのまとまりとして扱われる最小の単位ごとに行われることが多くそれを単体テストと呼びます。

結合テスト

単体テストに対して複数のモジュールを組み合わせて正しく連結できるかどうかを調べるテストを「結合テスト」「統合テスト」「連結テスト」「インターフェーステスト」などと呼びます。システム全体を対象に行うテストは「システムテスト」というそうです。


■結論(テストを書いて思ったこと)

テスト課題をして、テストする項目をどこまでテストするかは要件や考え方にもよって人それぞれなので難しいな〜と思いました。例えば、本のappのテストで目的はDBから何らかの値を画面に表示できているかをテストするのであれば全ての項目(タイトル、内容、著者、作成日など)をテストしなくてもよかったりします。調べるポイントを見極めて、何がテストできていればOKなのかを判断するのは難しい! 私は全てをテストしようとしていました...笑 また、テストが通ったのでOKではなく、失敗することを確認するまでが1つのテストで失敗するテストを怠ってはいけないと反省しました。

■モデルテスト(単体テスト)で学んだ点

  • 不要なファイルや使っていないfixture、変数は削除する

  • Time.zone.todayDate.currentは両方今日の日付を取ってきてくれる。Railsapplication.rbファイルのタイムゾーンの設定から日付を持ってくるのでTokyo時間の設定にしているか要確認!

  • created_onとは?:作成日(date)。created_atが作成日時で、created_onは日にちだけ返すメソッド

self.from_omniauthメソッドの単体テスト
def self.from_omniauth(auth)
  find_or_create_by(provider: auth.provider, uid: auth.uid) do |user|
    user.name = auth.info.name
    user.email = auth.info.email
    user.password = Devise.friendly_token[0, 20]
  end
end
  • self.from_omniauth(auth)の引数に何が入っているのか調べると、omniauth_callbacks_controller.rbファイルのgithubメソッドに記載してあるUser.from_omniauth(request.env['omniauth.auth'])request.env['omniauth.auth']の部分が渡されている
  • request.env['omniauth.auth']というリクエストパラメータには、OmniAuthによってHashのデータ構造に似たOmniAuth::AuthHashというクラスのオブジェクトが格納されている
  • OmniAuth::AuthHashクラスのオブジェクトのテストモードをOmniAuth.config.test_mode = trueで設定する
  • モック(テストサンプル)を作るにはmock_authを使うと、結合テスト中に認証プロバイダごとの認証ハッシュなどを返すことができる

参考:[Devise How-To] OmniAuth: 結合テスト(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

class UserTest < ActiveSupport::TestCase
  test '#self.from_omniauth' do
    OmniAuth.config.test_mode = true
    OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(
      {
        provider: 'github',
        uid: '12345',
        info: {
          name: 'carol',
          email: 'carol@example.com'
        },
        credentials: {
          token: Devise.friendly_token[0, 20]
        }
      }
    )
  assert User.from_omniauth(OmniAuth.config.mock_auth[:github])
end

システムテスト(結合テスト)で学んだ点

  • 削除した項目を確認するテストはassert_no_textを使って削除した項目がないことを確認できる

  • 今日の日付がviewで表示されているかを確認するときは、assert_text Date.current.strftime('%Y/%m/%d')で確認できる。Rubystrftimeメソッドは与えられた雛型で日付を書式できる。 Date#strftime (Ruby 3.0.0 リファレンスマニュアル)

  • 同じ画面にユーザ名が2つ:例えばAさんでログイン中とコメントの作成者にAさんと表示されていた場合にコメントを削除するテストでは、with inでclassの範囲指定して記載されているのかを確認するテストができる ※画面に表示されている数だけ調べたい場合であればassert_text 'Aさん', maximum: 2とテストを書くこともできる

within '.class名' do
  assert_no_text 'Aさん'
end

まとめ

  • テストは失敗することも必ず確認してテストを書くようにする。