RSpecでshared_examples_forを使って共通動作をテストする

先日からguard + spork + rspecを使った自動テストを行うようになってノリノリでテストをしています。いちいち自分でテストを走らせないでいいので便利ですね!sporkのおかげでテストのロードも速くて快適です。

さて、現在仕事でもゴリゴリとテストを書いているのですが、同じような処理を毎回書くことがあります。例えば、ユーザーの権限が管理者・会員・ゲストなどがある場合、それぞれの権限での動作を検証しなければなりません。でも権限毎に同じ振る舞いのテストを書いていると冗長ですよねぇ…。
会社で@kazuhisa1976@ore_publicと一緒にThe RSpec Book読書会をやっているのだけれど、そこで学んだ検証方法で、共通処理をまとめることができることを知りました。それが、shared_examples_forとit_behaves_likeです。

使い方ですが、まずはユーザーの振る舞いの検証をやっていきましょう。
まずは全部書いたやつ。以下のテストが全て通るとします。
(factory_girlをfixture生成で使っています)

# coding: utf-8
require 'spec_helper'

describe User do
  context "管理者の場合" do
    subject { FactoryGirl.create(:user, type: "admin") }
    its(:name) { should == "hogehoge" }
    its(:email) { should == "hogehoge@example.com" }
    its(:type) { should == "admin" }
  end
  context "会員の場合" do
    subject { FactoryGirl.create(:user, type: "normal") }
    its(:name) { should == "hogehoge" }
    its(:email) { should == "hogehoge@example.com" }
    its(:type) { should == "normal" }
  end
  context "ゲストの場合" do
    subject { FactoryGirl.create(:user, type: "guest") }
    its(:name) { should == "hogehoge" }
    its(:email) { should == "hogehoge@example.com" }
    its(:type) { should == "guest" }
  end
end

はい、冗長ですねぇ〜。各権限毎にテストしていますが、type以外の検証は全て同じです。

これをshared_examples_forを使ってリファクタリングしましょう。
まず、shared_examples_forで共通の振る舞いを定義します。

shared_examples_for "ユーザーの各権限共通の動作" do
  its(:name) { should == "hogehoge" }
  its(:email) { should == "hogehoge@example.com" }
end

共通の検証項目をここに書き出すだけです。
そして、実際の各ユーザーの検証部分では、it_behaves_likeで呼び出します。

context "管理者の場合" do
  subject { FactoryGirl.create(:user, type: "admin") }
  it_behaves_like "ユーザーの各権限共通の動作"
  its(:type) { should == "admin" }
end

では、これで全部書き直してみます。

# coding: utf-8
require 'spec_helper'

describe User do
  shared_examples_for "ユーザーの各権限共通の動作" do
    its(:name) { should == "hogehoge" }
    its(:email) { should == "hogehoge@example.com" }
  end
  context "管理者の場合" do
    subject { FactoryGirl.create(:user, type: "admin") }
    it_behaves_like "ユーザーの各権限共通の動作"
    its(:type) { should == "admin" }
  end
  context "会員の場合" do
    subject { FactoryGirl.create(:user, type: "normal") }
    it_behaves_like "ユーザーの各権限共通の動作"
    its(:type) { should == "normal" }
  end
  context "ゲストの場合" do
    subject { FactoryGirl.create(:user, type: "guest") }
    it_behaves_like "ユーザーの各権限共通の動作"
    its(:type) { should == "guest" }
  end
end

権限毎の検証項目が多くても短く記述することが可能になりますね!
テストは割とコピペで量産していることが多かったのですが、これでまとめられることがわかったので、色んなところでリファクタリングできそうです。


カテゴリー Ruby, Ruby on Rails | タグ | パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です