「EFFECTIVE TESTING WITH RSPEC 3: BUILD RUBY APPS WITH CONFIDENCE」の1章を読んだ
あとから読みなおせるようにブログにまとめつつ読んでいます。
Effective Testing with RSpec 3: Build Ruby Apps with Confidence
- 作者: Myron Marston,Ian Dees
- 出版社/メーカー: Pragmatic Bookshelf
- 発売日: 2017/09/09
- メディア: ペーパーバック
- この商品を含むブログを見る
EFFECTIVE TESTING WITH RSPEC 3: BUILD RUBY APPS WITH CONFIDENCE
は、直訳すると「RSpec3による効率的なテスト: 自信をもってRubyのアプリケーションを組み立てる」みたいな感じでしょうか。
英語版で読む理由
- 翻訳されてない
- 英語学習のため
- 英語で体系的な学習をする練習をするため
注意点
自分の解釈だったり誤訳も含んで日本語にしています。
序文(Foreword)
ソフトウェア開発は覚えることがたくさんあって大変だ。テストを書くこともそのうちの一つかもしれない。
しかし、ソフトウェア開発にテストを書くことは、欠かせない。
そして(Railsで)よいテストコードを書くためにRSpecは欠かせない。
RSpecは単なるテストフレームワークでなく、批判的に、根気よく、体系的に自分のコードの設計について考える方法と、体系的な手法でソフトウェアを開発する方法を学ぶためのツールでもある。
はじめに(Introduction)
「俺らのテストがまた落ちたよ!」
「なんでこの一連のコードが通るまでにこんなに時間がかかるんだ?」
「こんなテストになんの価値があるんだろう?」
テクノロジーは変わったけどテストへの不満の内容は変わらない。
この本では「効果的な(EFFECTIVE)」なテストの書き方を教えるよ。
効果的っていうのは、「わざわざ時間を割いて書く意味がある」ってことだ。
1章 RSpecをはじめよう
(Chp1 Getting Started With RSpec)
RSpecは生産的なテストフレームワークだ。スタイル、API、ライブラリ、設定、それら全てが最高のソフトウェア開発を手助けしてくれる。
いいテストから得られる効果は少なくともこれだけある。
設計ガイド
ドキュメント(仕様書)
最初のSpec
サンドウィッチを例にあげて考える。
RSpecはdescribeとitによって、まるで会話文のように表現することができる。
"Describe an ideal sandwich" (理想的なサンドウィッチについて説明してくれ)
"First, it is delicious" (はじめに、それはおいしい)
RSpecではこう書く。
RSpec.describe 'An ideal sandwich' do it 'is delicious' do end end
テストケースを加えたものが以下だ。
RSpec.describe 'An ideal sandwich' do it 'is delicious' do sandwich = Sandwich.new('delicious', []) taste = sandwich.taste expect(taste).to eq('delicious') end end
specはspecification(仕様書)の短縮形だ。
RSpec.describe ブロックは「例の集合*1」をつくる。
例の集合が何をテストしているか明らかにして、(今回だとサンドウィッチ)、関連するspecsを一つにまとめるんだ。
ネストされたブロック 'is delicious' はサンドウィッチの使い方の例だ。(他のフレームワークだとテストケースって呼ぶかもしれない)
コラム: テスト対スペック対イグザンプル (Tests vs. Specs vs. Examples)
テストはコードが正確に動くかvalidate(検証)する
スペックはコードに振る舞ってほしい動きをdescribe(説明)する
イグザンプルは特定のAPIがどのように使われるかを明らかにする
さて、ここでおさらいしておこう。
- RSpec.describe が例の集合をつくる
- it が例単体をつくる
- expect が期待される結果をあらわす
この3つがRSpecの核だ。どんなに長い道のりも、この3つを使えば前には進むことが出来る。
また、サンドウィッチspecから得られる目的は2つ。
- サンドウイッチに振る舞ってほしい挙動のドキュメント化
- サンドウィッチがあるべき姿かどうかのチェック
サンドウィッチspecのよいところは、「あたらしくプロジェクトに参画した人」のドキュメントになるってことだ。 specを読めば、サンドウィッチはおいしくなきゃならないってのがすぐにわかる。
セットアップの共有(Sharing Setup)
一つずつ順に見ていこう。
RSpecフック(before)
beforeは、itごとに準備されるRSpecフックだ。
Sandwich = Struct.new(:taste, :toppings) RSpec.describe 'An ideal sandwich' do before { @sandwich = Sandwich.new('delicious', [])} it 'is delicious' do taste = @sandwich.taste expect(taste).to eq('delicious') end it 'let me add toppings' do @sandwich.toppings << 'cheese' toppings = @sandwich.toppings expect(toppings).not_to be_empty end end
ここでは、@sandwichを使ったけど、インスタンス変数には実は欠点もある。
別のアプローチを試してみよう。
ヘルパーメソッド
RSpecは便利だから、ときにそれがRubyの支配下であることを忘れるけど、メソッドを定義することだって可能なんだ。
def sandwich @sandwich ||= Sandwich.new('delicious', []) end
このようなテクニックはメモ化(memoization)*2と呼ぶ。
この手法は便利だけど、落とし穴がないわけじゃない。||=は@sandwichがnilかfalseのときに働くから、@sandwichにnilかfalseを格納することはできなくなる。
こういった問題を解決する手段として、RSpecにはletが用意されている。
letでオブジェクトを共有する(Sharing Objects with let)
さきほどのsandwichメソッドを以下のコードに置き換えてみよう。
let(:sandwich) { Sandwich.new('delicious', [])}
letは「sandwichという名前と、ブロック{}を結びつけるもの」と考えてもいい。 このletによって、ちょうど先程のメモ化したヘルパーメソッドのように、それぞれのイグザンプルはsandwichが呼ばれた「最初のとき」だけブロックを評価するんだ。
コード共有テクニックを使うさいの注意点
これらのテクニックは、保守性を向上させ、ノイズを減らし、コードを明瞭にするために使おう。
あなたの番(Your Turn)
エクササイズ
さて、RSpecのお気に入りの使い方と出会う準備は出来てる?
サンドウィッチ休憩をとったら、次のチャプターで会おう。
エクササイズと自分の感想
エクササイズ1をやってみた
1はbeforeでよさそうだな〜。@sandwichの各属性に対するテストだからitごとにインスタンス変数を準備しておくことに違和感を感じない。
複数のインスタンスを複合的に使ったりする場面ではletのがいいのかも?
エクササイズ2をやってみた
rspec -e STRINGを実行した。 STRINGに指定した文字列に対して、itの後ろの文字列( 'is delicious'等)がマッチしたものだけテストが走る。 ヘルプに「何回も使うかもね」って書いてた。
感想
読んで訳してブログにするのに4時間ぐらいかかったーー。 作業自体は(疲れるけど)楽しいから、ちょっと頭の体操したいときの息抜きかなあ。 そして、著者がRSpec大好きなことが伝わってきて読んでて面白い。
頑張って2章もやりたい…!!