読者です 読者をやめる 読者になる 読者になる

Programming log - Shindo200

イベント参加記録とプログラミング系の雑記

パーフェクト Rails を読みました(7章)

この記事は『パーフェクト Rails を読みました』シリーズの7回目の記事です。
前回の記事は『パーフェクト Rails を読みました(6章) - Programming log - Shindo200』です。

前回の記事を投稿してから間があいてしまったのですが、『パーフェクト Ruby on Rails』の7章を読み終えましたので、記録を残しておきます。

パーフェクト Ruby on Rails

パーフェクト Ruby on Rails

7章の感想

7章ではテスティングフレームワークの使い方、MVC に対してのテストコードの書き方、TDDの進め方を学んでいきます。普段から Rspec + Capybara + FactoryGirl を使ってテストコードを書いていたり、『TDD Boot Camp』というイベントでTDDの思想について勉強していたりしましたので、この章はさくさくと読めました。

合わせて読みたい記事:TDDBC長岡に参加してきました - Programming log - Shindo200
※手前味噌ですが、未だに読み返すことが多いので紹介しました。

5章〜7章で便利なgemやCIサービスがたくさん紹介されていましたので、読んでいるだけで「自分でWebサービスを開発して、運用したい!」という気持ちが沸いてきて、体がうずいてしまいます。この書籍、恐ろしいです。

備忘録

Model, View, Controller に対してそれぞれテストすべきこと

Model に対してテストすべきこと

  • メソッドが期待通りの値を返すか
  • メソッドが期待通りの副作用をもたらしているか
  • バリデーションが正しく設定されているか

View に対してテストすべきこと

  • 期待通りのhtml片が出力されているか

Controller に対してテストすべきこと

  • アクションがビューに渡すインスタンス変数に期待通りのオブジェクトを代入しているか
  • アクションが期待通りのステータスコードを返しているか
  • アクションが期待通りのテンプレートを選択しているか

should-matchers

バリデーションやリレーションなどのテストで使える様々なマッチャーを提供する should-matchers という gem があります。

試しに、この gem を使ってバリデーション関連のテストコードを書いてみます。

class BlogEntry < ActiveRecord::Base
  validates :title, length: { maximum: 50 }, presence: true
end

# RSpec
describe BlogEntry do
  it { should validate_presence_of(:title) }
  it { should ensure_length_of(:title).is_at_most(50)
end

とても簡潔に書くことができますね。テストを実行すると以下のようなメッセージが出力されます。

$ .bin/bundle exec rspec spec/models/blog_entry_spec.rb

BlogEntry
  should require title to be set
  should ensure title has a length of at most 50

Finished in 0.03148 seconds (files took 1.42 seconds to load)
2 examples, 0 failures

fixture replacement

テストを実行する前にあらかじめテスト用のデータを作成しておきたい場合、Rails 標準付属の fixture という機能を使ってテスト用のデータを作成しておきます。fixture では Yaml 形式でテスト用のデータの内容を書いておきます。簡単に使うことができますので、シンプルなWebアプリを作るときはこれで十分だと思うのですが、開発の現場ではより便利な機能を持つ fixture replacement という種類のライブラリが利用されています。The Ruby Toolboxで人気の fixture replacement を調べてみました。(2014/06/22 現在)

f:id:Shindo_Masaya:20140622211334p:plain:w600

FactoryGirl という gem が圧倒的に人気ですね。

Rspec のexpect記法とshould記法について

Rspec3 が正式リリースされ、should記法を使うと警告が出るようになりました。Rspec3 ではexpect 記法を使ってください。ちなみに、BasicObject を継承したクラスに対して should を使うとテストが通らないことがあるので、expectという新しい記法を作ったようです。(BasicObject を継承するというのはすごく稀なケースだと思うのですが……そうでもないのでしょうか?)

参考: Myron Marston » RSpec's New Expectation Syntax

どうしても Rspec3 でshould記法が使いたい場合、以下のような設定を spec_helper.rb などに記述しておくことで Rspec3 でもshould記法が使えるようです。

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
    # should記法を使う(expect記法を使うと警告を出す)
    expectations.syntax = :should

    # expect記法を使う(should記法を使うと警告を出す)
    expectations.syntax = :expect

    # どちらの記法も使う
    expectations.syntax = [:should, :expect]
  end
end

capybara-webkit などのドライバと一緒に database_cleaner をインストールすべき理由

データベースからデータの削除を行う database_cleaner という gem があります。capybara-webkit などのドライバを使う場合は、必ず一緒にインストールしておいてください」という話しを聞いたことがあったのですが、何故一緒にインストールしないといけないのでしょうか。

『パーフェクト Ruby on Rails』P.262 から引用します。

テスト中にデータベースを操作した場合、テストケース毎にデータベースの状態を元に戻さないといけません。Railsはデフォルトでは、データベーストランザクションの機能を利用して、テストケース毎にデータベースをロールバックすることで状態を元に戻しています。しかし、seleniumやpoltergeist、capybara-webkitなどのドライバは、テストケースとして実行されるプロセスとは別にサーバ用のプロセスを作ります。トランザクション中の変更は別のプロセスからは見れません。そのため、これらの別プロセスを起動するドライバを利用したテストを行う場合、Railsデフォルトの設定ではデータベースの変更内容を見ることができません。

capybara-webkit などのドライバからデータベースを操作した場合、ドライバがデータベースをどのように変更したのかテスティングフレームワークは知ることができないから、テスト前の状態に正しく戻すことができず、データベースにデータが残ってしまう。だから、ドライバを使うときは、データベースの削除を行う gem (detabase_cleanerなど)を一緒にインストールしないといけない……ということですね。

お疲れ様でした

8章では「DevOps」について触れるようです。「自分でWebサービスを開発して、運用したい!」という気持ちが沸いてきたタイミングで「DevOps」ネタがあるのはとても嬉しいです。