RSpecは非常に優秀なテストフレームワークなので毎度お世話になっております。
テストをガンガン書いて質を高めて行くのは良いのですが、なんとなくそれをやり続けていると、じわりじわりと壊れやすいテストが邪魔してくるようになります。
なのでRSpecのテストコードを柔軟にしていくためにリファクタリングしたいなーと思った次第。まずはsubjectを切り出す方面でやってみます。
こんなコード
下記のようなDBテーブルを準備しました。
Migrationファイル
1 2 3 4 5 6 7 8 9 10 11 |
class CreateItems < ActiveRecord::Migration def change create_table :items do |t| t.string :name t.integer :price t.boolean :salable t.timestamps end end end |
FactoryGirl使います(詳細は割愛)。
1 2 3 4 5 6 7 |
FactoryGirl.define do factory :item do name "MyString" price 100 salable false end end |
Item#find_over_priceというメソッドのテストを書きます。このメソッドは引数に与えられた値以上のpriceを持つレコードを返すメソッドです。
テストパターンとしては、
- 500円以上のレコードが存在する場合は抽出される
- 500円以上のレコードが存在しない場合は抽出されない
としました。するとこんな感じのテストコードになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
require 'spec_helper' describe Item do describe "#find_over_price" do it "500円以上のitemが抽出されること" do create(:item, price: 500) items = Item.find_over_price(500) expect(items.count).to be > 0 end it "500円未満のitemが抽出されないこと" do create(:item, price: 499) items = Item.find_over_price(500) expect(items.count).to eq 0 end end end |
こんな感じの実装でグリーンになります。
1 2 3 4 5 |
class Item < ActiveRecord::Base def self.find_over_price(price) where("price >= ?", price) end end |
「items = Item.find_over_price(500)」が二度出現していて冗長ですね。二度で済めばいいですが、こういうテストコードを書くと、テストケースを追加するときにコピペしちゃったりして同じコードが増殖しがちです。
そこで、下記のように subject を使って共通のテスト対象を切り出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
require 'spec_helper' describe Item do describe "#find_over_price" do subject(:items) { Item.find_over_price(500) } it "500円以上のitemが抽出されること" do create(:item, price: 500) expect(items.count).to be > 0 end it "500円未満のitemが抽出されないこと" do create(:item, price: 499) expect(items.count).to eq 0 end end end |
このようにするとsubjectのブロックで実行された結果が、expectのレシーバになります。ちなみにこの例では、subjectに別名(items)をつけています。
減った行数はたった1行ですが、it内のコードが少なくなるのはテストの意図が明確になるので良いかと思います。また、subjectという表現でテスト対象のオブジェクトが明確化されるので読みやすくなるんではないかと。
ちょっと今回例が悪かったかな?的確な例を作るのが困難だったもんで。

原田 敦

最新記事 by 原田 敦 (全て見る)
- Rails Engineでブログ機能追加するgemを作る - 2015年3月15日
- WEBエンジニア一人だけでサービスを作りきる方法-夫婦のための自動ごはん予定お知らせサービス「GoHaaan」制作でやったこと - 2015年3月7日
- CentOS6でMariaDBのDynamic Columnsを試してみた - 2015年2月28日