Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

BDD by Jasmine (jscafe 13)

javascriptでjasmine使ってBDDする話。

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to comment

BDD by Jasmine (jscafe 13)

  1. 1. BDD by jasmine Ryuma Tsukano jsCafe13
  2. 2. ● BDDについて ● jasmineの基本文法 ● TDDのプロセスをハンズオン 今日の目次
  3. 3. ● javascript上でBDDをするためのtest framework ○ assertion/testdouble等、testに必要な機能全部入ってる ● 主にUTをカバーするもの =>BDDとは? jasmineとは
  4. 4. BDDとは
  5. 5. Behaivor Driven Development ● 振る舞い 駆動 開発 ● Dan North氏が提唱したもの。 振る舞い=そのシステムの動作仕様の事 ● ①specification : 詳細設計付近で定義されるような細かな動作の事 ● ②story : 要求仕様付近のアプリの動作の事 ※後述するが、それぞれツール群が異なる =>つまり、仕様から始める開発方法 ● 当たり前。 ● =>なぜ、こんな事を言ってるか? BDD
  6. 6. 元々BDDはTDDから派生したもの。 ● TDD:テスト駆動開発 by Kent Beck ->本 幾つか代表的な特徴を上げると、 ● テスト作業をプログラムで書く ● 実装の前にテストを書く(Test First) ● 初めに通過するcodeを書いてその後書き直して行く(Refactoring) いわゆるxUnitが普及 =>Junit始め各言語で出てきた。 Dan North=TDDの教育者。教えた現場の中で、 ● TDDが上手くいく現場と、 ● TDDが上手く行かない現場があった。 Dan NorthとTDD
  7. 7. <BAD> TDDがうまくいかない現場の様子 ● 何を書くかで悩む ● 工数が膨らむ? 原因 ● 彼らは「テスト」の観点でTDDを実施していた。 <GOOD>TDDがうまくいっている現場の様子 ● 何を書くかで悩まない ● 工数が削減? ● 副産物の効果に気づいてる(後述) 原因 ● 彼らは「設計」の観点でTDDを実施していた。 ● (&結果としてテスト)も出来た。 2patternの現場
  8. 8. TDDの観点として本当の意味でのテストをすると... ● 何をtestするか?で悩む ● 膨大な量のテストを書く事に ● 自動化難しいtestも書く? ● 追加改修時直す所沢山 =>とても大変な事に! また、TDD = テストと認識すると =>別の手段で詳細設計LVの事をしてしまう現場も有り =>TDD=設計(※後述)とすると、2重に設計作業してる事になる。 =>設計で2倍の工数がかかる。 TDDとテスト 引用元:http://www.hayst.com/Pages/positioning.aspx
  9. 9. TDDしてる瞬間 ● test書いてる時 ○ これから書くソースのロジック考える ■ =>詳細設計/プログラム設計してる ● test書いた後 ○ これを残してあげてる事で次の人に役立つ。like API仕様書 ■ =>詳細設計/API仕様書/IF仕様etc書いてる =>実は設計してる(&結果として、それがテストの一部に) =>TDDが上手く機能している現場は、これに気づいていた。 TDDする時にテストから設計にフォーカスを移すと... TDDと設計 テスト 設 計
  10. 10. TDDで設計すると(テストするTDDと比べて) ● 観点が明快なのでテストソース作りで悩む事が少なくなる。 ● テストの量が効果的に減る ○ テストソースも見通しが良くなる ○ 後での変更の量も少なめ ● 結果として後でも仕様として意味のあるテストが残る ○ TDDでテスト:仕様として冗長で分かり辛い ○ TDDで設計:第3者が見て仕様を把握し易い ● 位置づけを設計と明示=>事前に詳細設計的な作業を含まない ○ =>さっきのような誤って工数2倍が起こり辛い 実はKentBeckもTDDはテストというより設計(分析)と言ってる =>設計を前面にした方が正しい。 TDDで設計する効果
  11. 11. TDD(Test Driven Development) = テスト < 設計なんじゃん! ● テストって頭につくから勘違いされて失敗するんじゃんか。 ● 仕様/設計っぽい言葉(振る舞いBehaivor)を入れようぜ! =>そこでBehaiver Driven Development BDD(特にUT系のtool)の特徴(TDDと比べて) ● 自然言語で動作振る舞いを書く ○ TDD:method => BDD:describe “person” .. it “should have pen”.. ● 自然言語っぽく確認メソッドも書く ○ TDD: assert => BDD:shouldやexpect ● 自然言語の順で検証する「[実際値]は[期待値]と等しい」 ○ TDD:assert_equals 期待, 実際 => BDD:expect実際toBeEqual期待 ● 自然言語っぽく前提条件、後処理 ○ TDD : setup/teardown => BDD : before/after ※TDD系のToolもBDDっぽくなってるので、一概には言えないが... =>いずれにせよ自然言語的に振る舞う事を前面に出してる点が特徴 Dan North
  12. 12. 仮にテストする事を数値化したとすると ● 100%:やらなくてはいけないテスト ○ 60%:BDDが結果としてやるテスト(仕様として意味有) ○ 残り=40%。残ってる!この扱いは考えないといけない 残りの40%に対しての色んな考え方 ● ①テストしない(勿論、機能試験や受け入れ試験は実施するが) ○ 考え方:40をどこまで減らせる?に注力 ○ 「不安がある所をテスト(BDD)する」 ● ②昔ながらのSIっぽい網羅的な手動テストする ○ User多いor社会的な影響大きいと必然こうなる ● ③99%全部自動化する ○ 元の話に戻るが、こういう現場も ○ 保守/追加改修で、ただのテスト部分(上記の40)が邪魔になる ■ この部分(40)を後で削除する人達もいる=>自動化無意味? ○ 保守の為のTDD?設計の為のTDD?testの為の...とか言ってる =>求められている品質、納期に基づいて調整を 結局、テストはどこにいった?
  13. 13. ● 1)各言語でBDDツール出来た ○ ‘03 jBehave(java)から、C#版、php版、python版諸々出た ○ 初めはstory形式(given when then) => 結合テストより上 ● 2)rspec(ruby)が流行った。 ○ 結局、1のツールは普及しなかったが、rspecが流行った。 ○ rspecはspecifications形式(like TDD) => 単体テストをカバー ● 3)cucumber(ruby)が出てきた。 ○ 2)のrspecのstory runnerの話が膨らんでcucumberとして独立 ○ 1のstory形式をより洗練化=>表向き全部自然言語で書く ■ そこそこ流行った。 ● 4)jasmine(javascript)が出てきた。 ○ 元々jsUnit(xUnit系)作ってたPivotal社が改めて作った。≒ rspec ※最近jsではmocha(+chai等)が勢い有。BDDで書けばjasmineと大体一緒 BDDのその後の動き
  14. 14. jasmine
  15. 15. jasmineを始めましょう。 公式でふたつあり 1. stand alone・・・js単体で動作する物 2. ruby gem版・・・rails等ruby系frameworkの中で使うための物 1を使おう。 公式ページの一番下のDownloadsの 「stand alone release」を クリックしてダウンロード =>解凍してみよう! Let’s start jasmine
  16. 16. 本体(lib/specRunner)と、サンプルのjs(src)とその仕様(spec) ● lib : jasmineの本体。実行に必要なファイル。 ○ jasmine-html.js : html上のreport生成 ○ jasmine.css : そのcss ○ jasmine.js : jasmine本体 ● spec : サンプルの仕様(test) ○ PlayerSpec.js : サンプルのPlayer関数に対してのspec(test) ○ SpecHelper.js : 全体的な設定等を記載する所 ● src : サンプルのjsファイル ○ Player.js : サンプルのPlayer関数(≒class) ○ Song.js : サンプルのPlayerの使ってるSong関数(あえて開発中) ● SpecRunner.html : テスト結果を表示する(サンプルを実行) stand alone版
  17. 17. ブラウザでSpecRunner.jsを表示してみる =>サンプルのテストを実行 その結果 ● 抹茶色の帯 ○ 5つの仕様(spec)の確認に成功したと書かれている ● その下 ○ 振る舞いが書かれている ○ ex)PlayerはSongをplayできる ○ ex)songを停止した時 ■ songが現在停止を示す ■ 再開する事が出来る.. =>Jasmine実行結果から仕様が分かる SpecRunner.js
  18. 18. さっき、表示していたのは、コレ。 describe("Player", function() { var player; var song; beforeEach(function() { player = new Player(); song = new Song(); }); it("should be able to play a Song", function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); //demonstrates use of custom matcher expect(player).toBePlaying(song); }); spec/PlayerSpec.js
  19. 19. ● describe : suites ○ 意味のある仕様(spec)の集合 ■ ≒ディレクトリ的なもの。名前 ○ describeはnestできる ○ >第1引数:タイトルやパターン名等 ○ >第2引数:function(){ ※specs(複数の仕様)を書く } ○ 例)describe(“Player”, function() { … ■ describe(“when song has been paused”, function() { ... ● it : specs ○ 仕様 ■ ここにexpectaions(振る舞いの期待)を書く ○ >第1引数:どう振る舞うか自由に記述 ○ >第2引数:function() { ※expectaion(振る舞い期待)を書く} ○ 例)it(“should be able to play a Song” , function() { ... describeとit
  20. 20. expectation : 振る舞いの記述 ● expect(実際の値).マッチャー(期待値) 例) playerのcurrentlyPlayingSongプロパティに songが入ってる事を確認したい it("should be able to play a Song", function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); =>意図通り :SpecRunner.htmlでpass =>誤っている:SpecRunner.htmlでfailure ● 試しに、上のsongを”fake”にしてみると.. expectation
  21. 21. 書き方:to□□□□(期待値) ● expect(x).toEqual(y) : xはyと等しい ● expect(x).toBeTruthy() : xはtrueである ● expect(x).toContain(y) : xはyを含む(x = 配列か文字列) ● expect(x).toBeGreaterThan(y) : xはyより大きい ● 他、多数 自作matcherも作れる matcher
  22. 22. addMatchers({ 自作matcher名 : function(期待値) { ... ※この中でactual = 実際の値を使える return 真偽 } }); =>全体で使いたければ、SpecHelper.jsに書く 例)現在の歌と期待値が同じ、かつ演奏中である事を確認するmatcher this.addMatchers({ toBePlaying: function(expected) { var player = this.actual; return player.currentPlayingSong === expected && player.isPlaying; } }); // これが、src/SpecHelper.jsに書いてある 自作matcher
  23. 23. 前提条件 ● beforeEach(function () { … 前提条件となる処理 } ); ○ 後処理は、同じ書き方でafterEach 例)前提条件としてテスト対象となるplayer/song関数をnewする beforeEach(function() { player = new Player(); song = new Song(); }); 実行順)itの度にbeforeEachする describe(“suites”, function() { [a] beforeEach(function() { ... }) [b] it(“specs-first”, function() { … }); [c] it(“specs-second”, function() { … }); => 実行順 [a] => [b] => [a] => [c] 前提条件
  24. 24. spy : test doublesを実現するための仕組み ● test doubles=テスト対象が依存してるcomponentを置換する仕組み テスト対象だけを確認したいのに、 依存する外部のコンポーネントに何か理由があって、 確認が出来ない時に、外部のコンポーネントを 別のものに置換する、というもの。 実際はfake/dummy/mock/stub/spyと色々あるがjasmineでは意識しない jasmineとtest doubles テストソース jasmine テスト対象 js 依存する外部の コンポーネント js
  25. 25. ● まだ実装されてないコードの代替 ○ 実際、これが一番一般的なシチュエーション? ● slow test対策 ○ 特にDB等ioに関する処理は遅い=>遅い所を置換する ● 外部のリソースアクセス ○ 例)某位置SNSのAPIよく落ちてる=>testの成否が不安定化 ■ このAPIを置換しておけばUTの結果は安定 ● ※UnitTestはこれでいいが、このエラーはエラーで対応考 えないといけないのでご注意を。 ● 純粋なUnitTestをするため ○ 教科書的にはComponent TestとUnit Testは違う test doublesはいつ使う?
  26. 26. ● spyOn(対象constructor, 関数名) ○ =>これで実装がどうであれ仮の関数が作り出される ● expect(実際の値).toHaveBeenCalledWith(期待する引数) ○ =>期待する引数で仮の関数を使っている事を確認する it("tells the current song if the user has made it a favorite", function() { // ★これ (src/Song.js見るとpersistFavoriteStatusはエラーを返す) spyOn(song, 'persistFavoriteStatus'); player.play(song); player.makeFavorite(); // この中でsong.persistFavoriteStatusを実行 // ★これ (player.makeFavoriteの中でtrue引数で実行を確認) expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true); jasmineのtestdouble
  27. 27. spyオブジェクト.andReturn(期待する戻り値) 例) spyOn(song, 'persistFavoriteStatus').andReturn("success!"); expect(song.persistFavoriteStatus()).toEqual("success!"); ※この例はあまり意味が無いけど、前述のように 例えばtestする関数が使用してる別の関数が出来てない時等で使う spy.andReturn
  28. 28. TDD(BDD)のプロセスをハンズオン
  29. 29. 今からサンプルにソースを追加してBDDの一通りの流れを見てみる <やりたい事> Player.jsに ● volumeプロパティを追加 ● setVolume()を追加 ○ setVolume()にvolumeが0〜100の範囲かのvalidationを追加 ○ この範囲内:volumeプロパティ=値を入れて「true」を返す ○ この範囲外:「false」を返す ※setterでtrue/false返すのおかしくないか? 的なツッコミは置いておいて!気にしないで!>_< ただの例なの! BDDしてみよう
  30. 30. 失敗=>成功=>Refactoring TDDの流れ RED (fail) GREEN (pass) Refactor Start
  31. 31. TDDの流れ ● 0:やるべきタスクを整理 ○ todoを作る(by kent beck) => jasmineのdescribe/itで良いかと ● 1:仮実装(Fake it) ○ Red)仮のtest書く=>元が無いので失敗 ○ Green)とにかくtestに通過する仮の実装をする ○ Refactor)一旦整理 ● 2:三角測量(triangulate)=>明白な実装(obvious implementation) ○ Red)三角測量するtestを書く=>失敗 ○ Green)実際の処理を実装(明白な実装)=>成功 ○ Refactor)汚くなったら整理 その後、適宜Refactoring。 もし、何かしらの原因でRedになったらGreenになるべく調整 具体的な流れ
  32. 32. ①−1)// spec/PlayerSpec.js 最後の括弧とじの前に以下を追加 describe("#setVolume", function() { it("can set 80", function() { expect(player.setVolume(80)).toEqual(true); }); }); => SpecRunner.html : Red(失敗) ①−2)// src/Player.js Player.prototype.setVolume = function() { return true; }; => SpecRunner.html : Green(成功) このガリガリのハードコーディングが仮実装 ※specの確認をしてる。正しい値があればspec動くか?の確認 ①仮実装
  33. 33. 同じテスト対象に対して異なる入力値を与える(=三角測量) ②−1)// spec/PlayerSpec.js it("can not set 200(>= 100)", function() { expect(player.setVolume(200)).toNotEqual(true); }); => SpecRunner.html : Red(失敗) ②−2)ここで正しく実装する。(=明白な実装) // src/Player.js Player.prototype.setVolume = function(volume) { this.volume = volume; if(0 <= volume && volume <= 100){ return true; } else { return false;} }; => SpecRunner.html : Green(成功) ②三角測量=>明白な実装
  34. 34. todo=>仮実装=>三角測量=>明白な実装 ● TDD(BDD):設計で悩むときは、頭の中で考えるより、とりあえず手を動か していった方がいい。 ○ そのための、プロセスを提示している ● 逆に、特に悩む事が無ければ、いきなり明白な実装しても良い ○ 絶対的なルールではない。 それぞれ意味がある ● todo ○ やる事を整理 ● 仮実装 ○ 正しいテストを作る ● 三角測量 ○ 入力値にはパターンがある事を認識 ● 明白な実装 ○ 上記踏まえて実装 TDDの進め方
  35. 35. BDDとは ● TDDから派生。 ● テストでなく設計を前面に出したもの。 ○ =>そうした方が悩まなくて済む jasmine ● describe { }とit { }で囲む ● expect( … ).マッチャーで確認 ● spyでtest double TDDのプロセスハンズオン ● 基本:テスト失敗=>成功=>リファクタリングの繰り返し ● 流れ:いきなり明白な実装しても良いが、悩んだら、以下 ○ todo整理=>仮実装=>三角測量=>明白な実装 まとめ
  36. 36. おしまい

×