SlideShare ist ein Scribd-Unternehmen logo
1 von 33
RSpec のここがすごい! RSpec で宣言的な UnitTest! RSpec ? Ruby には、 Test::Unit があるし、 普通に UnitTest が書けるよね? なんで??
RSpec のここがすごい! RSpec で宣言的な UnitTest! まずはこれを見てくれ require 'lru_cache' describe LruCache do describe " を初期化する場合 " do it " は、サイズを渡したら、そのサイズのキャッシュができる ." do targ = LruCache.new(10) targ.limit.should == 10 end it " もし、サイズにマイナス値を渡したら、例外が発生する ." do lambda{ LruCache.new(-1) }.should raise_error(ArgumentError) end it " もし、サイズに nil を渡したら、例外が発生する ." do lambda{ LruCache.new(nil) }.should raise_error(ArgumentError) end it " もし、サイズに数値以外を渡したら、例外が発生する ." do lambda{ LruCache.new("a") }.should raise_error(ArgumentError) end end end http://github.com/mitim/tddbc-lrucache/blob/master/lru_cache_spec.rb
RSpec のここがすごい! RSpec で宣言的な UnitTest! 1.  まず  LruCache に関する 記述 (describe) だよ、と宣言して 1.  そのうちの「初期化をする場合」のテストだよ、と宣言して 1.  「サイズを渡したら、そのサイズのキャッシュができる」べきだと、通常できることを説明していて 1.  その内容で targ.limit は 10 であるべき (should) と明示して 2.  「サイズにマイナス値を渡したら、例外が発生する」べきだと、引数がおかしい場合に起こることを説明していて 1.  その内容で  ArgumentError という error が発生するべきと明示して 3.  「サイズに nil を渡したら、例外が発生する」べきだと、引数がおかしい場合に起こることを説明していて 1.  その内容で  ArgumentError という error が発生するべきと明示して 4.  「サイズに数値以外を渡したら、例外が発生する」べきだと、引数がおかしい場合に起こることを説明していて 1.  その内容で  ArgumentError という error が発生するべきと明示して これを見るだけで、 LruCache が 「何をするプログラムなのか」 が見えてくる ! しかも、 Test::Unit ( Java の JUnit4.1 以前相当)よりも、より 記述が簡便 で読みやすい !
UnitTest の次の流れ -より人が 読みやすい テストへ RSpec で宣言的な UnitTest! UnitTest が広まるなかで、認識されていったこと 1. UnitTest は、ホワイトボックス・テスト ( テスト対象の全コードを理解したうえ  でのテスト ) ではない 。 2. UnitTest でテストしているのは、テスト対象のクラスとメソッドの インタ フェース だ。 1.  つまりは、ブラックボックス・テスト、ステートボックス・テストに 他な らない 。 3.  インタフェース の肝とは、インプットとアウトプットが何であるかをしっかり 確立すること。 1.  つまりは、その インタフェース の振る舞いをしっかり確立すること。 そうだ! 振る舞い をテストするんだ!!
UnitTest の次の流れ -より人が 読みやすい テストへ ,[object Object],RSpec で宣言的な UnitTest! だったら、振る舞いをもっとわかりやすく記述できないかな? ,[object Object]
-> Ruby  の場合  : RSpec  の登場 いずれでも、根底にある思想は「 コードは徹頭徹尾人が読むためにある存在 」だということ。
ブラックボックス? ステートボックス? RSpec で宣言的な UnitTest! どちらかというと 設計 に該当する考え方。しかし、そのコードに与える影響の強さは、フローチャート以上。 ブラックボックスやステートボックスの考え方自体は、構造化手法とそれに伴うモジュール化の時代から存在している。
ブラックボックス? ステートボックス? RSpec で宣言的な UnitTest! ブラックボックス・テスト? ブラックボックスとは、あるクラスの公開アクセッサに注視して、その インタフェース を明らかにすること。 じっさいの コードやオブジェクトの状態は考慮に入れない で行う。 クラス ,[object Object]
ブラックボックス? ステートボックス? RSpec で宣言的な UnitTest! メソッド / プロパティ ,[object Object]
IN 値に特値(特別な値)があるときは、その値
IN 値がオブジェクトの場合:そのステートに制限があるときは、ステート ,[object Object],[object Object]
単なる無動作 ,[object Object],[object Object]
IN 値に特値があるときは、その場合の OUT 値
クラスにステートがあり、それにより OUT 値が左右される場合は、ステート別の OUT 値
ブラックボックス? ステートボックス? ステートボックス・テスト? ステートボックスとは、あるクラスの オブジェクトのステート やそのクラスが 他に及ぼす影響 に注視して、そのステート・影響を明らかにすること。 じっさいの コードは考慮に入れない で行う。 クラス RSpec で宣言的な UnitTest! ,[object Object]
RSpec で宣言的な UnitTest! ブラックボックス? ステートボックス? メソッド / プロパティ ,[object Object]
IN 値と現ステートの組み合わせによるステートの変化値 ,[object Object],[object Object]
システム的なオブジェクトなど、自身に管理権限のない他のオブジェクトへの影響 ,[object Object],[object Object]
システム的なオブジェクトなど、自身に管理権限のない他のオブジェクトからの影響
RSpec で宣言的な UnitTest! ブラックボックス? ステートボックス? これらのインタフェースを意識していくと しぜんに、次のような設計を心がけるようになっていく。 1.  メソッドの 引数には、なるべく閾値を設けない 。設ける場合も、列挙(enum)を使 うなどして閾値外にならないように工夫する。 2.  クラスの ステートは、必要最低限に構成する ようになる。複数のステートが絡み複 雑になる場合は、クラス分けを考え出す。 3.  外部への 影響は、なるべく排除する ように考え出す。外部からの影響(変更可能 性)も必要最低限へ。 TDD ではどう扱うか? 1.  どうテストを書いたらいいかわからなくなった!そんな時の指針になる。 2.  ただし、あまりガチガチに縛られないように。
RSpec  のやる事、やらない事 RSpec のやる事 RSpec のやらない事 ,[object Object]
即座に UnitTest を実行して、その結果をすぐに得られる。
モックやスタブを使える。 ,[object Object],[object Object],[object Object],[object Object],RSpec で宣言的な UnitTest!
RSpec の構文 なにはなくとも require require  'lru_cache' テスト対象のファイル を読み込ませる。 ちなみに、RSpecの何かをrequireする必要なない。 RSpec で宣言的な UnitTest!
RSpec で宣言的な UnitTest! RSpec の構文 まずは基本 describe  do end で、一番外側のブロックを記述する。 通常は、次のようにテスト対象のクラスを宣言しておく。 また、一緒に説明を付けることも可能。 describe   LRUCache  do end describe   LRUCache ,  " を初期化する場合 "  do end もちろん、説明だけにすることも可能。  describe   "LRUCache のケース "  do end
RSpec の構文 RSpec で宣言的な UnitTest! describe の中 describeの中にもdescribeを重ねられる たとえば、同じクラスのテストでも、 初期化のテストをがっつりやって、 次にhogeメソッドのテスト、 そしてfugaメソッドのテストを …とやっていくと、 必然的にテストが長く見づらくなってくる 。 たとえば、 hogeメソッドのテストと fugaメソッドのテストとでは、 前準備で必要なものがぜんぜん違う 。 そんなときには、 describe のなかにさらに describe を書いて 、整理をつけることができる。
RSpec の構文 RSpec で宣言的な UnitTest! describe の中 describeの説明文 ここに何を書くべきか。 自然に仕様書っぽく構成した文書にしたいなら、次のように気をつけて記述してみるといい。 [ クラス名 ] ,  “[ て / に / を / は / の ]○○ する場合 ( ケース )” ※クラス名は、ひとつ上のdescribeでまとめてしまった方が記述がスッキリするのは、 言うまでも無い。
RSpec の構文 RSpec で宣言的な UnitTest! describe の中 テストの前準備 before テスト本文(it)を実行する前に必要な、 テストと直接は関係ない準備のための処理 を記述する。 たとえば、テスト対象のオブジェクトを生成して、インスタンス変数に入れたり。 たとえば、モックやスタブを用意して、本物のオブジェクトと摩り替えたり。 たとえば、ファイルを用意したり。  before  :each do end before  :all do end :each を指定した before は、各テスト (it) のたびに、その前に必ず実行される。 :all を指定した before は、 describe の最初に一度だけ実行される。
RSpec の構文 RSpec で宣言的な UnitTest! describe の中 テストの後処理 after テスト(it)を実行した後に必要な、 テストと直接は関係ない後片付けのための処理 を記述する。  after  :each do end after  :all do end :each を指定した after は、各テスト (it) を実行するたびに、その後に必ず実行される。  :all を指定した after は、 describe の最後に一度だけ実行される。
RSpec の構文 RSpec で宣言的な UnitTest! it の中 テストのコードは、すべて it の中に記述する。 基本的な書き方は、次のとおり。  it  " テストの説明 "  do [ テスト対象オブジェクト ] . [ テスト対象メソッド ] .should ==  [ 結果 ] end
RSpec の構文 RSpec で宣言的な UnitTest! it の中 ここに何を書くべきか。 自然に仕様書っぽく構成した文書にしたい場合、次のように気をつけて記述してみるといい。 "[ どのような操作をする ] と、 [ その結果はどうなる ] 。 " itの説明文 基本的な機能要件を説明する場合 特殊な機能要件や、エラー的な機能要件を説明する場合 “ は、○○すると、 ×× になる。” “ もし、○○すると、 ×× になる。”
RSpec の構文 RSpec で宣言的な UnitTest! it の中 shouldメソッドは、そのオブジェクトの状態を確認し、指定された状態であるか否か( ~であるべき )を検査する。 ==  演算子のほか、 be 系の Matcher が多数用意されている。 全てのオブジェクトに動的に加えられたメソッドなので、基本的には何でも検査可能。 shouldメソッド should_notメソッド shouldと違い、こちらは否定検査( ~であってはいけない )をするときに使用する。
RSpec の構文 RSpec で宣言的な UnitTest! it の中 shouldで検査できるよう、多数のMatcherが用意されている。 Matcher群 == expected ==比較の結果が同じか be_true 真であるか be_false 偽であるか be_nil nilか be_empty Arrayが空か be_an_instance_of Class クラスがClassと一致するか be_a_kind_of Class クラスが指定Class、もしくはそのサブクラスか == expected ==比較の結果が同じか be_true 真であるか be_false 偽であるか be_nil nilか be_empty Arrayが空か be_an_instance_of Class クラスがClassと一致するか be_a_kind_of Class クラスが指定Class、もしくはそのサブクラスか

Weitere ähnliche Inhalte

Andere mochten auch

MacRuby Jogo Rapido
MacRuby Jogo RapidoMacRuby Jogo Rapido
MacRuby Jogo RapidoDiogo Santos
 
S Spw Ppt Edit
S Spw Ppt EditS Spw Ppt Edit
S Spw Ppt EditKonevo311
 
Acqueon - RAP CMS Data Bridge - Presentation
Acqueon - RAP CMS Data Bridge - PresentationAcqueon - RAP CMS Data Bridge - Presentation
Acqueon - RAP CMS Data Bridge - PresentationAcqueon Technologies Inc.
 
Inverted Nipple Correction
Inverted Nipple CorrectionInverted Nipple Correction
Inverted Nipple CorrectionSHAILESH NISAL
 
Keylingo Translations Summary
Keylingo Translations SummaryKeylingo Translations Summary
Keylingo Translations Summarythemarxhouse
 
Интернет для индустрии красоты
Интернет для индустрии красотыИнтернет для индустрии красоты
Интернет для индустрии красотыFert
 
Russia
RussiaRussia
Russiamazavr
 
Migration To The United States Of America
Migration  To  The  United  States Of  AmericaMigration  To  The  United  States Of  America
Migration To The United States Of America13aadx
 
Installing the oracle bi mobile app designer
Installing the oracle bi mobile app designerInstalling the oracle bi mobile app designer
Installing the oracle bi mobile app designerRavi Kumar Lanke
 
Creating new service name for oracle database
Creating new service name for oracle databaseCreating new service name for oracle database
Creating new service name for oracle databaseRavi Kumar Lanke
 
Earn More, Save More Or Invest Wisely V2
Earn More, Save More Or Invest Wisely V2Earn More, Save More Or Invest Wisely V2
Earn More, Save More Or Invest Wisely V2Sudhir Agarwal
 
[HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0...
 [HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0... [HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0...
[HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0...Santuário do Mestre Ryu
 
Strategie nutrizionali nella corsa gjav integratori ferrara
Strategie nutrizionali nella corsa gjav integratori ferraraStrategie nutrizionali nella corsa gjav integratori ferrara
Strategie nutrizionali nella corsa gjav integratori ferraraGJAV
 
Chicago (Group schoolwork project)
Chicago (Group schoolwork project)Chicago (Group schoolwork project)
Chicago (Group schoolwork project)Sonny Brabez
 

Andere mochten auch (20)

Orientations Inventory
Orientations InventoryOrientations Inventory
Orientations Inventory
 
Infomil als informatiepunt over het Activiteitenbesluit
Infomil als informatiepunt over het ActiviteitenbesluitInfomil als informatiepunt over het Activiteitenbesluit
Infomil als informatiepunt over het Activiteitenbesluit
 
UCV IEEE fam ss
UCV  IEEE fam ssUCV  IEEE fam ss
UCV IEEE fam ss
 
MacRuby Jogo Rapido
MacRuby Jogo RapidoMacRuby Jogo Rapido
MacRuby Jogo Rapido
 
S Spw Ppt Edit
S Spw Ppt EditS Spw Ppt Edit
S Spw Ppt Edit
 
Acqueon - RAP CMS Data Bridge - Presentation
Acqueon - RAP CMS Data Bridge - PresentationAcqueon - RAP CMS Data Bridge - Presentation
Acqueon - RAP CMS Data Bridge - Presentation
 
Inverted Nipple Correction
Inverted Nipple CorrectionInverted Nipple Correction
Inverted Nipple Correction
 
Keylingo Translations Summary
Keylingo Translations SummaryKeylingo Translations Summary
Keylingo Translations Summary
 
Интернет для индустрии красоты
Интернет для индустрии красотыИнтернет для индустрии красоты
Интернет для индустрии красоты
 
Russia
RussiaRussia
Russia
 
에코바자회
에코바자회에코바자회
에코바자회
 
Portfolio
PortfolioPortfolio
Portfolio
 
Migration To The United States Of America
Migration  To  The  United  States Of  AmericaMigration  To  The  United  States Of  America
Migration To The United States Of America
 
Installing the oracle bi mobile app designer
Installing the oracle bi mobile app designerInstalling the oracle bi mobile app designer
Installing the oracle bi mobile app designer
 
Creating new service name for oracle database
Creating new service name for oracle databaseCreating new service name for oracle database
Creating new service name for oracle database
 
Earn More, Save More Or Invest Wisely V2
Earn More, Save More Or Invest Wisely V2Earn More, Save More Or Invest Wisely V2
Earn More, Save More Or Invest Wisely V2
 
Ca eed 2014 milan wg5 4 nl split incentive
Ca eed 2014 milan wg5 4   nl split incentiveCa eed 2014 milan wg5 4   nl split incentive
Ca eed 2014 milan wg5 4 nl split incentive
 
[HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0...
 [HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0... [HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0...
[HQ NACIONAL] STREET FIGHTER II - ANO I: NÚMERO 1 - Parte 4 ( Completo 10/ 0...
 
Strategie nutrizionali nella corsa gjav integratori ferrara
Strategie nutrizionali nella corsa gjav integratori ferraraStrategie nutrizionali nella corsa gjav integratori ferrara
Strategie nutrizionali nella corsa gjav integratori ferrara
 
Chicago (Group schoolwork project)
Chicago (Group schoolwork project)Chicago (Group schoolwork project)
Chicago (Group schoolwork project)
 

Ähnlich wie RSpecのここがすごい!

初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)Masahiro Hayashi
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタートShumpei Shiraishi
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Ransui Iso
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
最近の単体テスト
最近の単体テスト最近の単体テスト
最近の単体テストKen Morishita
 
初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)Masahiro Hayashi
 
RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数Altech Takeno
 
Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Takuya Tsuchida
 
Shibuya.lisp #28: 仮題: R について
Shibuya.lisp #28: 仮題: R についてShibuya.lisp #28: 仮題: R について
Shibuya.lisp #28: 仮題: R についてtnoda
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜Hiromi Ishii
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Rubymitim
 
Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)Eugene Yokota
 
JavaScript超入門 基礎
JavaScript超入門 基礎JavaScript超入門 基礎
JavaScript超入門 基礎tetsu6
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsShogo Sensui
 
Javascripでオブジェクト指向
Javascripでオブジェクト指向Javascripでオブジェクト指向
Javascripでオブジェクト指向1000 VICKY
 

Ähnlich wie RSpecのここがすごい! (20)

初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタート
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
最近の単体テスト
最近の単体テスト最近の単体テスト
最近の単体テスト
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)
 
svelte-ja.pdf
svelte-ja.pdfsvelte-ja.pdf
svelte-ja.pdf
 
R spec勉強会
R spec勉強会R spec勉強会
R spec勉強会
 
RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数
 
Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス
 
Shibuya.lisp #28: 仮題: R について
Shibuya.lisp #28: 仮題: R についてShibuya.lisp #28: 仮題: R について
Shibuya.lisp #28: 仮題: R について
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Ruby
 
Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)
 
JavaScript超入門 基礎
JavaScript超入門 基礎JavaScript超入門 基礎
JavaScript超入門 基礎
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.js
 
Spock's world
Spock's worldSpock's world
Spock's world
 
Rpscala2011 0601
Rpscala2011 0601Rpscala2011 0601
Rpscala2011 0601
 
Javascripでオブジェクト指向
Javascripでオブジェクト指向Javascripでオブジェクト指向
Javascripでオブジェクト指向
 

RSpecのここがすごい!

  • 1. RSpec のここがすごい! RSpec で宣言的な UnitTest! RSpec ? Ruby には、 Test::Unit があるし、 普通に UnitTest が書けるよね? なんで??
  • 2. RSpec のここがすごい! RSpec で宣言的な UnitTest! まずはこれを見てくれ require 'lru_cache' describe LruCache do describe " を初期化する場合 " do it " は、サイズを渡したら、そのサイズのキャッシュができる ." do targ = LruCache.new(10) targ.limit.should == 10 end it " もし、サイズにマイナス値を渡したら、例外が発生する ." do lambda{ LruCache.new(-1) }.should raise_error(ArgumentError) end it " もし、サイズに nil を渡したら、例外が発生する ." do lambda{ LruCache.new(nil) }.should raise_error(ArgumentError) end it " もし、サイズに数値以外を渡したら、例外が発生する ." do lambda{ LruCache.new("a") }.should raise_error(ArgumentError) end end end http://github.com/mitim/tddbc-lrucache/blob/master/lru_cache_spec.rb
  • 3. RSpec のここがすごい! RSpec で宣言的な UnitTest! 1. まず LruCache に関する 記述 (describe) だよ、と宣言して 1. そのうちの「初期化をする場合」のテストだよ、と宣言して 1. 「サイズを渡したら、そのサイズのキャッシュができる」べきだと、通常できることを説明していて 1. その内容で targ.limit は 10 であるべき (should) と明示して 2. 「サイズにマイナス値を渡したら、例外が発生する」べきだと、引数がおかしい場合に起こることを説明していて 1. その内容で ArgumentError という error が発生するべきと明示して 3. 「サイズに nil を渡したら、例外が発生する」べきだと、引数がおかしい場合に起こることを説明していて 1. その内容で ArgumentError という error が発生するべきと明示して 4. 「サイズに数値以外を渡したら、例外が発生する」べきだと、引数がおかしい場合に起こることを説明していて 1. その内容で ArgumentError という error が発生するべきと明示して これを見るだけで、 LruCache が 「何をするプログラムなのか」 が見えてくる ! しかも、 Test::Unit ( Java の JUnit4.1 以前相当)よりも、より 記述が簡便 で読みやすい !
  • 4. UnitTest の次の流れ -より人が 読みやすい テストへ RSpec で宣言的な UnitTest! UnitTest が広まるなかで、認識されていったこと 1. UnitTest は、ホワイトボックス・テスト ( テスト対象の全コードを理解したうえ でのテスト ) ではない 。 2. UnitTest でテストしているのは、テスト対象のクラスとメソッドの インタ フェース だ。 1. つまりは、ブラックボックス・テスト、ステートボックス・テストに 他な らない 。 3. インタフェース の肝とは、インプットとアウトプットが何であるかをしっかり 確立すること。 1. つまりは、その インタフェース の振る舞いをしっかり確立すること。 そうだ! 振る舞い をテストするんだ!!
  • 5.
  • 6. -> Ruby の場合 : RSpec の登場 いずれでも、根底にある思想は「 コードは徹頭徹尾人が読むためにある存在 」だということ。
  • 7. ブラックボックス? ステートボックス? RSpec で宣言的な UnitTest! どちらかというと 設計 に該当する考え方。しかし、そのコードに与える影響の強さは、フローチャート以上。 ブラックボックスやステートボックスの考え方自体は、構造化手法とそれに伴うモジュール化の時代から存在している。
  • 8.
  • 9.
  • 11.
  • 12.
  • 15.
  • 16.
  • 17.
  • 18.
  • 20. RSpec で宣言的な UnitTest! ブラックボックス? ステートボックス? これらのインタフェースを意識していくと しぜんに、次のような設計を心がけるようになっていく。 1. メソッドの 引数には、なるべく閾値を設けない 。設ける場合も、列挙(enum)を使 うなどして閾値外にならないように工夫する。 2. クラスの ステートは、必要最低限に構成する ようになる。複数のステートが絡み複 雑になる場合は、クラス分けを考え出す。 3. 外部への 影響は、なるべく排除する ように考え出す。外部からの影響(変更可能 性)も必要最低限へ。 TDD ではどう扱うか? 1. どうテストを書いたらいいかわからなくなった!そんな時の指針になる。 2. ただし、あまりガチガチに縛られないように。
  • 21.
  • 23.
  • 24. RSpec の構文 なにはなくとも require require 'lru_cache' テスト対象のファイル を読み込ませる。 ちなみに、RSpecの何かをrequireする必要なない。 RSpec で宣言的な UnitTest!
  • 25. RSpec で宣言的な UnitTest! RSpec の構文 まずは基本 describe do end で、一番外側のブロックを記述する。 通常は、次のようにテスト対象のクラスを宣言しておく。 また、一緒に説明を付けることも可能。 describe LRUCache do end describe LRUCache , " を初期化する場合 " do end もちろん、説明だけにすることも可能。 describe "LRUCache のケース " do end
  • 26. RSpec の構文 RSpec で宣言的な UnitTest! describe の中 describeの中にもdescribeを重ねられる たとえば、同じクラスのテストでも、 初期化のテストをがっつりやって、 次にhogeメソッドのテスト、 そしてfugaメソッドのテストを …とやっていくと、 必然的にテストが長く見づらくなってくる 。 たとえば、 hogeメソッドのテストと fugaメソッドのテストとでは、 前準備で必要なものがぜんぜん違う 。 そんなときには、 describe のなかにさらに describe を書いて 、整理をつけることができる。
  • 27. RSpec の構文 RSpec で宣言的な UnitTest! describe の中 describeの説明文 ここに何を書くべきか。 自然に仕様書っぽく構成した文書にしたいなら、次のように気をつけて記述してみるといい。 [ クラス名 ] , “[ て / に / を / は / の ]○○ する場合 ( ケース )” ※クラス名は、ひとつ上のdescribeでまとめてしまった方が記述がスッキリするのは、 言うまでも無い。
  • 28. RSpec の構文 RSpec で宣言的な UnitTest! describe の中 テストの前準備 before テスト本文(it)を実行する前に必要な、 テストと直接は関係ない準備のための処理 を記述する。 たとえば、テスト対象のオブジェクトを生成して、インスタンス変数に入れたり。 たとえば、モックやスタブを用意して、本物のオブジェクトと摩り替えたり。 たとえば、ファイルを用意したり。 before :each do end before :all do end :each を指定した before は、各テスト (it) のたびに、その前に必ず実行される。 :all を指定した before は、 describe の最初に一度だけ実行される。
  • 29. RSpec の構文 RSpec で宣言的な UnitTest! describe の中 テストの後処理 after テスト(it)を実行した後に必要な、 テストと直接は関係ない後片付けのための処理 を記述する。 after :each do end after :all do end :each を指定した after は、各テスト (it) を実行するたびに、その後に必ず実行される。 :all を指定した after は、 describe の最後に一度だけ実行される。
  • 30. RSpec の構文 RSpec で宣言的な UnitTest! it の中 テストのコードは、すべて it の中に記述する。 基本的な書き方は、次のとおり。 it " テストの説明 " do [ テスト対象オブジェクト ] . [ テスト対象メソッド ] .should == [ 結果 ] end
  • 31. RSpec の構文 RSpec で宣言的な UnitTest! it の中 ここに何を書くべきか。 自然に仕様書っぽく構成した文書にしたい場合、次のように気をつけて記述してみるといい。 "[ どのような操作をする ] と、 [ その結果はどうなる ] 。 " itの説明文 基本的な機能要件を説明する場合 特殊な機能要件や、エラー的な機能要件を説明する場合 “ は、○○すると、 ×× になる。” “ もし、○○すると、 ×× になる。”
  • 32. RSpec の構文 RSpec で宣言的な UnitTest! it の中 shouldメソッドは、そのオブジェクトの状態を確認し、指定された状態であるか否か( ~であるべき )を検査する。 == 演算子のほか、 be 系の Matcher が多数用意されている。 全てのオブジェクトに動的に加えられたメソッドなので、基本的には何でも検査可能。 shouldメソッド should_notメソッド shouldと違い、こちらは否定検査( ~であってはいけない )をするときに使用する。
  • 33. RSpec の構文 RSpec で宣言的な UnitTest! it の中 shouldで検査できるよう、多数のMatcherが用意されている。 Matcher群 == expected ==比較の結果が同じか be_true 真であるか be_false 偽であるか be_nil nilか be_empty Arrayが空か be_an_instance_of Class クラスがClassと一致するか be_a_kind_of Class クラスが指定Class、もしくはそのサブクラスか == expected ==比較の結果が同じか be_true 真であるか be_false 偽であるか be_nil nilか be_empty Arrayが空か be_an_instance_of Class クラスがClassと一致するか be_a_kind_of Class クラスが指定Class、もしくはそのサブクラスか
  • 34. RSpec の構文 RSpec で宣言的な UnitTest! it の中 Matcher群 have_key key keyがあるか be_close E,D 数値が、E~Dの範囲に収まっているか change receiver,message,&block Procオブジェクトが変化するか change(receiver,message,&block).by value Procオブジェクトが指定された値で変化するか(should_notは使用できない) change(receiver,message,&block).from(before).to(after) Procオブジェクトがbeforeからafterに変化するか(should_notは使用できない) eql expected ==とほぼ同義((eql?で比較) equal expected 同じオブジェクトか have(n).items 配列などのコレクションオブジェクトが、n個の要素を持っているか。 have_exactly(n).items 配列などのコレクションオブジェクトが、ちょうどn個の要素を持っているか。(should_notは使用できない) have_at_least(n).items 配列などのコレクションオブジェクトが、n個以上の要素を持っているか。(should_notは使用できない) have_at_most(n).items 配列などのコレクションオブジェクトが、n個以下の要素を持っているか。(should_notは使用できない)
  • 35. RSpec の構文 RSpec で宣言的な UnitTest! it の中 Matcher群 include expected 配列などのコレクションオブジェクトに、expectedが入っているか。 match regexp 正規表現regexpにマッチするか。 raise_error 例外が発生するか。 raise_error Expected Expectedな例外が発生するか。 raise_error Expected,message Expectedな例外が、messageを伴って発生するか。 raise_error Expected,regexp Expectedな例外が、正規表現にマッチするメッセージを伴って発生するか。 respond_to method,method,method... オブジェクトが、指定メソッドを全て持つか。 satisfy {|e| ...} ブロックの実行結果(eにテストオブジェクトが渡される)が真になるか。 thorw_symbol(symbol=nil) symbolがthrowされるか。 書いてる本人が、使ったことがないMatcherが多数。
  • 36. RSpec の構文 RSpec で宣言的な UnitTest! it の中 例外が発行されたかどうかはどうチェックする? 次のようにすると、例外の捕捉ができ、例外発行チェックができる。 proc{ [ターゲットオブジェクト].[ターゲットメソッド] }.should raise_error
  • 37. RSpec の構文 RSpec で宣言的な UnitTest! スタブ / モック機能 RSpecには、簡単なスタブとモックを組み込む機構が用意されている。 ここでは、RSpecのスタブ/モック機能に焦点を当てる。 簡単な機構なので、もっとダイナミックな仕組みが欲しい場合は、mochaやflex_mockなどのモック専用ライブラリ/フレームワークを利用した方が効率がいい。
  • 38.
  • 40. UnitTest が大きな問題に移ると段々と結合テスト化してしまう、という問題がある。 ある程度のスタブ/モックを使用することで、これらの問題が有機的にクリアされていく。 ※ ただし、スタブ/モックを多用し過ぎると、今度はインタフェース不一致の発見を先送りにする、という状況にもなりかねない。このあたりはさじ加減が必要。
  • 41. RSpec の構文 RSpec で宣言的な UnitTest! スタブ / モック機能 スタブとモックの違い では、スタブとモックの違いはなにか? 最近、 Martin Fowler らが、このスタブとモックの違いに関して面白い考察をしていた。この定義は今や一般化しており、RSpecでもこの意味でスタブとモックとを使い分けている。 スタブ 「 インタフェースの定義だけ一致 していれば、中身はどのように動いてもいいので、とりあえず用意しておく空箱」のことを言う。 モック 「インタフェースの定義だけではなく、 それがどの様に呼ばれるか、またそれに対して何を返すべきかまでを模倣 した空箱」のことを言う。
  • 42. RSpec の構文 RSpec で宣言的な UnitTest! スタブ / モック機能 スタブ 何かのクラスのアクセッサをスタブ化するときは、次の構文でアクセッサをスタブに摩り替える。 たとえば次のように書くと、Stringクラスのsizeメソッドが、必ず10を返却するようになる。 [クラス] .stub! (:[アクセッサ]) .and_return ([戻り値]) # [クラス]は[アクセッサ]をスタブ化し、[戻り値]を返す。 String .stub! (:size) .and_return (10)
  • 43. RSpec の構文 RSpec で宣言的な UnitTest! スタブ / モック機能 モック 何かのクラスのアクセッサをモック化するときは、次の構文でアクセッサをモックに摩り替える。 [クラス] .should_recieve (:[アクセッサ]) # [クラス]は[アクセッサ]が呼ばれることを期待する。 [クラス] .should_recieve (:[アクセッサ]) .and_return ([戻り値]) # [クラス]は[アクセッサ]が呼ばれることを期待し、その結果として[戻り値]を返す。 [クラス] .should_recieve (:[アクセッサ]) .with ([引数]) .and_return ([戻り値]) # [クラス]は[アクセッサ]が[引数]で呼ばれることを期待し、その結果として[戻り値]を返す。
  • 44. RSpec の構文 RSpec で宣言的な UnitTest! スタブ / モック機能 たとえば次のように書くと、Arrayクラスのsliceメソッドが引数(5,5)で呼ばれることを期待し、その結果として[5,6,7,8,9]を返却するようになる。 Array .should_recieve (:slice) .with (5,5) .and_return ([5,6,7,8,9]) モック
  • 45.
  • 47. RSpec を実行しよう! RSpec で宣言的な UnitTest! CI のなかでテストを通して行う場合 $ spec -c -fh [specコードファイル.rb] > result.html 次のようにすると、 HTML 形式で結果を出力してくれる。 出力したHTMLを特定HTTPサーバに配置するなり、メールに添付するなどまでを自動化すると、かなり使えるツールになる。