酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

Everyday Rails RSpecによるRailsテスト入門でRSpec3に再入門![書評]

largeEveryday Rails - RSpecによるRailsテスト入門』 が、RSpec3に対応したとの噂を聞いて1年ぶりに読み直しました。この書籍は著者や訳者さんが、しっかりとアップデートを続けてくれているので、最新の入門チュートリアル としてRspecの実践的な使い方が習得できる素晴らしい本です。

今回は『Everyday Rails - RSpecによるRailsテスト入門』 を読んでいく中で、特に印象に残った部分を中心にピックアップしていきます。ブログ駆動勉強ですw


Everyday Railsのサンプルソース

everydayrails/rspec_rails_4 - GitHub

この書籍ではできるだけRspecやテストに集中できるようにサンプルソースが用意されています。しかもRails4対応と至れり尽くせりです。素晴らしい! ターミナルで以下のコマンドを実行すると、ローカルにソースコードをダウンロードできます。

1
git clone https://github.com/everydayrails/rspec_rails_4.git

自分でコードを書く

勉強をするときにコピペをするのではなく、自分でコードをタイピングしていくべき。 これは最近学習によって得られる知識がかなり変わることを実感しているのですごく共感できます!

テスト設計について

TDDで動くコードを書く前にRSpecのexample(itで始まる行)まで書いてテスト設計する。 いつもテストが先か、コードが先かで悩んでいました。この理由の一つは動かない状態のテストの設計をどこに 書くかでしたが、この本を読んでいく中でこういうふうに先に設計すればTDDの流れの中で開発できるんだと感激ました^^

絶対に覚えておきたいRSpecを書くときの基本

* Specアウトラインをベースに考える
* example(itで始まる行)は原因究明しやすいように結果を1つに絞る
* 期待する結果は能動形、具体的に記述すること
* 「起きてほしいこと、起きてほしくないこと」の両方のテストを書くこと
* 境界値テストをすること
* スペックの可読性を高めることに努めること

コントローラスペックについて

feature specに比べてコントローラスペックのほうが、少ないコストでテストできる。 コントローラのテストは、自動生成されていないコードで、テストにコストをかけて効果が高そうなものを選定するといい。 その結果しっかりテストされたコントローラがあれば、アプリ全体のテスト網羅率を向上させることができる。

FactoryGirlのテクニック

以下のようにファクトリを書くことで、home_phonework_phoneを使わける事ができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FactoryGirl.define do
  factory :phone do
    association :contact
    phone '123-555-1234'

    factory :home_phone do
      phone_type: 'home'
    end

    factory :work_phone do
      phone_type: 'work'
    end
  end
end

また、『stympy/faker』を使うと、 住所やURL、メールアドレスなどのリアルなダミーデータを生成してくれます。

ただ日本語のふりがななどに対応しようと思うと『willnet/gimei』 がオススメです。日本語のリアルな住所を組み合わせたダミーデータも簡単に作成する事ができます。

FactoryGirlはテストを遅くすることがあるそうなので、必要なときに適切に使う事が重要とのことです。

shared_examples

shared_exmamplesとは、いくつかのテストをグループ化して、メソッドのように何度も呼び出せる機能です。 下は公式サンプルのテストですが、これを見るとひと目でわかると思います!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require "set"

RSpec.shared_examples "a collection" do
  let(:collection) { described_class.new([7, 2, 4]) }

  context "initialized with 3 items" do
    it "says it has three items" do
      expect(collection.size).to eq(3)
    end
  end

  context "with an an item that is in the collection" do
    it "returns true" do
      expect(collection.include?(7)).to be_truthy
    end
  end
end

RSpec.describe Array do
  # ↓shared_examplesを関数のように呼び出している
  it_behaves_like "a collection"
end
#=> Array
#=>   behaves like a collection
#=>     initialized with 3 items
#=>       says it has three items
#=>     with an an item that is in the collection
#=>       returns true

RSpec.describe Set do
  # ↓shared_examplesを関数のように呼び出している
  it_behaves_like "a collection"
end
#=> Set
#=>   behaves like a collection
#=>     initialized with 3 items
#=>       says it has three items
#=>     with an an item that is in the collection
#=>       returns true

FactoryGirlでローカルのファイルを指定する方法

1
2
3
4
5
6
# ローカルのファイルを指定する方法
FactoryGirl.define do
  factory :user do
    avatar { File.new("#{Rails.root}/spec/factories/avatar.png") }
  end
end

Rspecの便利マッチャー

1
2
3
4
5
# 正規表現でのチェック
expect("a string").not_to match /a regex/

# 配列のチェック
expect([1, 2, 3]).to match_array [2, 1, 3]

テストで特定の時間を指定する方法

travisjeffery/timecop - GitHub

特定の曜日や日にちに依存する処理がある場合に、そのテストをすることができる。また、時間を止めることができるのでタイムスタンプが正しく動いているかのテストなどができる。

メールのテスト

bmabey/email-spec -GitHub

EmailについてテストをするためのGem。知らなかったけどこれはすごい使えそう。今度試してみます!

RSpec 3初心者向けの資料まとめ

RSpec 3初心者向けの資料まとめ[Ruby]

ちなみにその他のTDDやRSpecの入門記事も書いています。こちらも良ければ是非読んでみてください^^

変更来歴

(2015-01-12 22:30) 既存記事から分離して新規作成

押さえておきたい書籍

いかがだったでしょうか?
もし説明がわかりにくかったり、間違っている場所があればぜひ一言!

Comments