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