SlideShare una empresa de Scribd logo
1 de 28
Descargar para leer sin conexión
今日から始めるTDD on Rails




                 東京大学文学部 3年 Takaya Kotohata
                           t.kotohata@gmail.com



12年12月25日火曜日
自己紹介

    • twitter @tii_kot


    • blog http://tkot.hatenablog.com/


    • github https://github.com/mhersmh


    • Rails歴1.5年


    • 最近はNode.jsとかErlangに注目してます




12年12月25日火曜日
テストは書かなきゃいけないの?

    • 書きましょう


    • 書くことで得られる知識は意外と広いので純粋に勉強になる


    • 慣れればブラウザをリロードが馬鹿らしくなる


    • デプロイ後のアプリケーションの可用性を高める


    • 継続的デリバリー




12年12月25日火曜日
逆に書かなくてもよいケースとは?

    • 金銭や人命にかかわらないアプリであること


    • Railsの基本的機能しか使っていないこと


    • とりあえず動いてます的なプロトタイプで十分なこと


    • 保守・運用の予定がないこと


    確かに上記をすべて満たせば書く必要はないか
    もしれない。


12年12月25日火曜日
Railsでよく使われるテストフレームワーク

    • Test::Unit Ruby標準ライブラリ。


    • shoulda Test::UnitをRSpec風に拡張してくれる。


    • RSpec 一番人気。


    • Cucumber 自然言語でシナリオを書いて、対応するユーザやアプリの動きを
      Rubyのコードで書く受け入れテスト


    DHHはTest::Unit派。それぞれ得意不得意があるのでプロ
    ジェクトごとにベストなものを選べばよいが、迷ったら
    RSpecを使えば間違いない
12年12月25日火曜日
RSpecとCucumberの組み合わせ

    • かなりメジャーな組み合わせ


    • Cucumberは自然言語で書かれたユーザストーリーをfeatureとして定義、開発
      者以外も読むことができるのが利点とされる


    • とはいえ本当に開発者以外が読むの?


    • RSpecとCucumberで異なるDSLを学習するコストがかかるので、RSpec一本
      でもいいような気がする。


    • だけど今日はCucumberも勉強します笑



12年12月25日火曜日
基本的なTDDの流れ

           ①要件定義・設計



         ②受け入れテスト作成



         ③設計・ユニットテスト    ④コーディング




                 ⑤リファクタリング

12年12月25日火曜日
各フローのアクション

    • 要件定義・設計・・・アプリケーションにどのような機能が必要か、どのよ
      うに画面は遷移するかなどを洗い出す。各リソースにどのような仕事分担をさ
      せるかなども考えるとよい


    • 受け入れテスト・・・これにパスしたら要件が満たされているというテス
      ト。ユーザーストーリーに対応し、ユーザの挙動をシミュレートするテストに
      なる。CucumberあるいはRequest Specに対応する。


    • 設計・ユニットテスト・・・最小単位で戻り値のオブジェクト型や必要なイ
      ンターフェースを設計・定義する


    • コーディング・・・ユニットテストをパスする最低限のコードをひとまず書
      き上げる




12年12月25日火曜日
よくある誤解

    • アジャイル開発は設計を厳格に定義せずにとりあえずコードを書いてみる手
      法だなんていう風に思ってるかもしれませんがそれは全く誤解です


    • Railsは最初のリソース設計でコケると先ほどの開発フローチャートをすべて
      やり直すことになる! 一つのイテレーションにおける要件定義と設計、画面
      遷移のイメージ確認などは十分時間をかけるべき


    • ドキュメントを書かないなんていうのも全く誤り。ドキュメント主体になら
      ないというだけで、設計について話しあったり将来的に追加されそうな機能
      は積極的にメモを残すべきだし、なるべくドキュメントも同一のバージョン
      管理下に置いたほうがいい。



12年12月25日火曜日
テストは完璧とは限らない

    • テストフレームワークに慣れてないうちはむしろテストの書き間違いのほうが
      圧倒的に多い


    • 受け入れテストの変更はイコール仕様変更なので問題ないが、ユニットテス
      トの変更は設計の変更レベルであり得て、しかもリファクタリング中に起こ
      りうる


    • そのため、「③で理想的設計を定義し、④から⑤に移行して終了」という流
      れがベストでも、「⑤から③に立ち戻る」というケースも多い。現実的に
      ③④⑤はグルグル回るが、やはり最終的にユニットテストをコードが通過して
      いればよい。



12年12月25日火曜日
受け入れテスト・ユニットテストとは何か

    • 受け入れ(acceptance)テスト=このテストを通過すればストーリーを満たして
      いると考えて良いテストのこと。「ユーザーがXXにアクセスして、idに⃝⃝、
      passwordに⃝⃝を入力してregisterボタンを押すと∼∼が行われる」のように
      実際の操作に近いテスト。


    • ユニット(単体)テスト=オブジェクトの振る舞いが期待されたもの通りかを検
      証する。たとえばMyObj#to_sメソッドはStringのインスタンスを返すこと
      を、いくつかのMyObjインスタンスに対してチェックする、など。




12年12月25日火曜日
よくある誤解2

    • ×ユニットテストはModelのテストのこと・・・Controllerでレスポンスが
      xx_pathにリダイレクトされる、などもユニットテストといえる。


    • ×ユニットテストはホワイトボックステストである・・・ホワイト~, ブラック
      ~は次元の異なる概念。プログラム構造に対して網羅的となるテストがホワイ
      トボックステストで、メソッド内の実装に踏み込まないテストがブラック
      ボックステスト。




12年12月25日火曜日
ユニットテスト(続き)

    • プログラムを利用する場合は、各オブジェクトにメッセージを送ってやり取
      りをするルーティンのほうに関心があるから、オブジェクトがすべき仕事を
      記述するユニットテストがTDD初心者には分かりにくい。


   具体例                                             UsersController#createをルーティン

   class UsersController < ApplicationController   で考えると、@user.saveでDBに保
    def create                                     存されるかどうかに関心を持ってし
      @user = User.new(params[:user])
                                                   まうが、DBに保存されるかどうか
      if @user.save
        redirect_to user_path(@user)                 はModelの仕事であるから、
      else                                         Controllerは単に@user.saveがtrueを
        render :new
                                                   返したらuser_pathにリダイレクト
      end
    end                                            し、そうでないならnewをrenderす
   end                                                 ることに注力すればよい


12年12月25日火曜日
テストファーストの最大の利点

    • テストを全く書かない場合、人間の思考はオブジェクトやメソッドがある実
      行コンテキストでどのような仕事をするかに集中しがち。


    • ユニットテストから書くことで各オブジェクトの仕事や領域、インターフェー
      スが明確となって疎結合なコードを書くことができる


    • 受け入れテストから書くことで実装の可否の基準が明確になる=仕様書を書
      くコストを別の資産に転換できる




12年12月25日火曜日
Cucumber(1)

  • Railsほど厳格な規約はないものの、例えばUserというリソースに対するテス
    トならfeatures/users/registration.featureのようにまとめると便利


  • 自然言語で書かれたfeatureと、その内容をコードの動作に解釈する
    step_definitionsが存在


  • features/step_definitions/user_steps.rbにUserのstepをまとめると良い


  • step_definitions内で使われるfill_inやclick_buttonなどのメソッドはwebratが提
    供するもの。




12年12月25日火曜日
cucumber(2)

   ⃝features/users/registration.feature (フィーチャー定義)
     もし メールアドレスはuser@example.com,パスワードはtesttest,ユーザ名はuser1で
   ユーザ登録をする


   ⃝features/step_definitions/user_steps.rb(ステップ定義)
   When /^メールアドレスは(.*),パスワードは(.*),ユーザ名は(.*)でユーザ登録をする$/ do |
   email, password, name|
    visit new_user_registration_path
    fill_in(“user_email”, with:email)
    fill_in(“user_password”, with: password)
    fill_in(“user_password_confirmation”, with: password)
    fill_in(“user_display_name”, with:name)
    click_button(“Sign up”)
   end

12年12月25日火曜日
cucumber(3)


    • Cucumberのstep_definitionsで書かれるコードはDBにレコードを投入するも
      のと、ブラウザの動きをシミュレートものの2種類が大半


    • 前者はもちろんActiveRecordなどのDSLが使用可能だが、後者はwebratある
      いはcapybaraが提供するメソッドを覚える必要がある(10~20種類くらい)


    • 現在は廃止されたが少し前までwebrat_ja_steps.rbなどの汎用的ステップ定義
      が提供されていた


    • 廃止されたのはフィーチャー定義が冗長になる原因だったから。



12年12月25日火曜日
webrat_ja_steps.rb

     #coding: utf-8
     When /^”(.*)”ボタンをクリックする$/ do |button|
       click_button(button)
     end
     When /^”(.*)”リンクをクリックする$/ do |link|
       click_link(link)
     end
     When /再読み込みする/ do
       visit request.request_uri
     end
     When /^”(.*)”に”(.*)”と入力する$/ do |field, value|
       fill_in(field, with: value)
     end
     などなど...




12年12月25日火曜日
Cucumber(4)


  シナリオ: 登録されていないmailとパスワードで新規登録
   もし “ユーザ登録ページ”へアクセス
   かつ “user_email”に”user1@example.com”と入力する
   かつ “user_password”に”testtest”と入力する
   かつ “user_display_name”に”user1”と入力する
   かつ “user_password_confirmation”に”testtest”と入力する
   かつ “Sign up”ボタンをクリックする
   ならば “You have signed up successfully.”と表示されていること

               冗長でわかりづらいし、再利用性に乏しい
                 (3つ前のスライドと比べてみよう)


12年12月25日火曜日
Cucumber(5)

    • featureに対して正規表現でマッチしたstepが呼び出される=2つ以上にマッチ
      してしまうとエラーになるので注意。曖昧なstepは書かない。


    • 引用符付きのstepとそうでないものがあるが、基本的には単なる文字列の一
      部なので好みの問題。囲ったほうが変数がわかりやすいかも。


    • stepの中で別のstepを再利用したり、tableでレコードを一度に登録するなど
      ができます。覚えてください。




12年12月25日火曜日
RSpec (1)

    • Cucumberがアプリケーションの仕様であるのに対して、RSpecはプログラム
      の仕様と考えるとわかりやすい


    • モジュールやクラスがどのようなメソッドを持って、そのメソッドはある引数
      に対してどのような結果を返すのか、などのプログラムレベルでのテスト


    • 最小レベルのテストで、対象の振る舞いだけに集中することが重要。例えば
      あるクラスをテストするときに他のクラスに処理を委譲する箇所があったと
      して、そちらの実装を気にせずにテストするためにオブジェクトやメソッド
      を偽物(Fake)化する、など




12年12月25日火曜日
RSpec(2)

    • RSpecはRailsに限定されたものではない。Railsで使う場合以下のようなテス
      トディレクトリが存在。(1)spec/controllers (2)spec/models (3)spec/helpers
      (4)spec/views (5)spec/libs (6)spec/routing (7)spec/requests (8)spec/support


    • requestはwebratなどを使用した受け入れテスト。Cucumberを使う場合はか
      ぶるので要らないと思う。


    • routingはconfig/routes.rbとイメージしているURLが合致しているかをテスト
      するだけなのでカバレッジを気にしないなら不要かも。


    • viewも頻繁に書き換わるところなので、書く必要はないかもしれない。



12年12月25日火曜日
RSpec(3)

    • 逆に書くべきなのはspec/models, spec/controllers, spec/libs, spec/helpers。


    • Controllerのspecでは、あるルーティングにHTTPリクエストを飛ばした時に
      想定しているオブジェクトに想定しているメッセージを送っているかを検証
      =モデルの適切なメソッドを(適切な引数で)呼び出しているか、responseに
      flashは含まれるか、想定しているURLにリダイレクトしているか、などをテス
      トする


    • Modelのspecでは、定義したメソッドが正しい挙動をしているか、実際に
      メッセージを送って戻り値を検証するのがメイン。例外の発生やファイルが
      作成されるかなども検証できる。



12年12月25日火曜日
RSpec(4)

                                   describe UsersController do
  ※stub(:save).and_return(false)     describe “POST create” do
  実際にsaveされるかはここでテスト                  describe “with invalid params” do
  しない。偽のメソッドによってfalse                  it “re-render the ‘new’ template” do
  を返させる。                                 User.any_instance.stub(:save).and_return(false)
                                           post :create, {user: {name: “test”}}
                                           response.should render_template(“new”)
  ※should テストの核の部分。これを                 end
  エクスペクテーションとかアサー                     end
                                     end
  ションと言う。
                                   end




12年12月25日火曜日
RSpec(5)

    • 各種のマッチャを覚える必要がある。


    • 基本的にはitブロックの中に1つのエクスペクテーションを書く。


    • エクスペクテーションごとに共通化できる処理はメソッドにして呼び出す
      か、beforeにまとめるなどが可能


    • describe(context)は各テストをグルーピングできる。グルーピングによってテ
      ストケースがわかりやすくなるほか、before/afterなどのフックをグループご
      とに定義可能になってうれしい。




12年12月25日火曜日
RSpec(6)

    • スタブとモックは本物の代用となるコード。


    • スタブはインターフェースを提供するが、モックはエクスペクテーションも提
      供する。


    • つまり以下のコードで下は@user.nameが呼ばれないとテストが通らない。




               @user.stub(:name).and_return(“hogehoge”)       スタブ
               @user.should_receive(:name).and_return(“hogehoge”)   モック




12年12月25日火曜日
RSpec(7)

    • double,mock,stubの概念とRSpecにおける語用には隔たりがあるので注意。
      RSpecが提供するmock(Obj)とstub(Obj)はdouble(Obj)のエイリアスである。


    • rspec-railsが提供するmock_modelとstub_modelという拡張がある。例えば
      form_forヘルパーに対してどのように応答するオブジェクトを渡すべきか知ら
      ずに済ませたい=>mock_modelを使えばActiveRecordオブジェクトの基本的
      な応答をスタブ化できる


    • mock_modelとstub_modelの違い=>stub_modelは実際のActiveRecordオブ
      ジェクトを作成する。ただしDBとのやり取りを行わない(saveや
      update_attributesを呼び出すとエラーになる)



12年12月25日火曜日
TDD実践編 今回作るアプリケーション

    • Twitterのようなアプリケーションを作りましょう


    • 認証(devise)を含むテストも書いてみます


    • デザインは作る気はないので、flash[:info]やi18nなどはかなり適当にやります


    • https://github.com/t-kot/tdd_on_rails




12年12月25日火曜日

Más contenido relacionado

Similar a Tdd

DrupalでBDDテストを実施してみる①
DrupalでBDDテストを実施してみる①DrupalでBDDテストを実施してみる①
DrupalでBDDテストを実施してみる①iPride Co., Ltd.
 
使い捨て python コードの書き方
使い捨て python コードの書き方使い捨て python コードの書き方
使い捨て python コードの書き方Sho Shimauchi
 
テスト自動化読書会 第3章 20150523
テスト自動化読書会 第3章 20150523テスト自動化読書会 第3章 20150523
テスト自動化読書会 第3章 20150523dnoguchi
 
Let s database_testing
Let s database_testingLet s database_testing
Let s database_testingYuji Shimada
 
PHPフレームワーク入門
PHPフレームワーク入門PHPフレームワーク入門
PHPフレームワーク入門Sho A
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門Yasuko Ohba
 
PerlとSQLのいろいろ
PerlとSQLのいろいろPerlとSQLのいろいろ
PerlとSQLのいろいろTakuya Tsuchida
 
C# から java へのプログラム移植で体験したtddの効果は?
C# から java へのプログラム移植で体験したtddの効果は?C# から java へのプログラム移植で体験したtddの効果は?
C# から java へのプログラム移植で体験したtddの効果は?Shinichi Hirauchi
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogrammingMasanori Kado
 
20100324 勉強会資料(ドメイン駆動)
20100324 勉強会資料(ドメイン駆動)20100324 勉強会資料(ドメイン駆動)
20100324 勉強会資料(ドメイン駆動)Masayuki Kanou
 
JS開発におけるTDDと自動テストツール利用の勘所
JS開発におけるTDDと自動テストツール利用の勘所JS開発におけるTDDと自動テストツール利用の勘所
JS開発におけるTDDと自動テストツール利用の勘所Koji Nakamura
 
さわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPさわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPNSaitoNmiri
 
Jubatusでマルウェア分類
Jubatusでマルウェア分類Jubatusでマルウェア分類
Jubatusでマルウェア分類Shuzo Kashihara
 
大規模なJavaScript開発の話
大規模なJavaScript開発の話大規模なJavaScript開発の話
大規模なJavaScript開発の話terurou
 
⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2Nishida Kansuke
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Rubymitim
 
2015-12-16 某S社、出直しDDDってるってよ
2015-12-16 某S社、出直しDDDってるってよ2015-12-16 某S社、出直しDDDってるってよ
2015-12-16 某S社、出直しDDDってるってよkumake
 

Similar a Tdd (20)

DrupalでBDDテストを実施してみる①
DrupalでBDDテストを実施してみる①DrupalでBDDテストを実施してみる①
DrupalでBDDテストを実施してみる①
 
使い捨て python コードの書き方
使い捨て python コードの書き方使い捨て python コードの書き方
使い捨て python コードの書き方
 
テスト自動化読書会 第3章 20150523
テスト自動化読書会 第3章 20150523テスト自動化読書会 第3章 20150523
テスト自動化読書会 第3章 20150523
 
Let s database_testing
Let s database_testingLet s database_testing
Let s database_testing
 
PHPフレームワーク入門
PHPフレームワーク入門PHPフレームワーク入門
PHPフレームワーク入門
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門
 
PerlとSQLのいろいろ
PerlとSQLのいろいろPerlとSQLのいろいろ
PerlとSQLのいろいろ
 
C# から java へのプログラム移植で体験したtddの効果は?
C# から java へのプログラム移植で体験したtddの効果は?C# から java へのプログラム移植で体験したtddの効果は?
C# から java へのプログラム移植で体験したtddの効果は?
 
Tdd
TddTdd
Tdd
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
 
20100324 勉強会資料(ドメイン駆動)
20100324 勉強会資料(ドメイン駆動)20100324 勉強会資料(ドメイン駆動)
20100324 勉強会資料(ドメイン駆動)
 
Slick入門
Slick入門Slick入門
Slick入門
 
JS開発におけるTDDと自動テストツール利用の勘所
JS開発におけるTDDと自動テストツール利用の勘所JS開発におけるTDDと自動テストツール利用の勘所
JS開発におけるTDDと自動テストツール利用の勘所
 
さわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPさわってみようTOPPERS/SSP
さわってみようTOPPERS/SSP
 
Jubatusでマルウェア分類
Jubatusでマルウェア分類Jubatusでマルウェア分類
Jubatusでマルウェア分類
 
大規模なJavaScript開発の話
大規模なJavaScript開発の話大規模なJavaScript開発の話
大規模なJavaScript開発の話
 
Rspec
RspecRspec
Rspec
 
⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Ruby
 
2015-12-16 某S社、出直しDDDってるってよ
2015-12-16 某S社、出直しDDDってるってよ2015-12-16 某S社、出直しDDDってるってよ
2015-12-16 某S社、出直しDDDってるってよ
 

Más de Takaya Kotohata

Más de Takaya Kotohata (6)

Kotohata profile
Kotohata profileKotohata profile
Kotohata profile
 
Unix5
Unix5Unix5
Unix5
 
詳解UNIXプログラミング 第4章 ファイルとディレクトリ
詳解UNIXプログラミング 第4章 ファイルとディレクトリ詳解UNIXプログラミング 第4章 ファイルとディレクトリ
詳解UNIXプログラミング 第4章 ファイルとディレクトリ
 
Unix3
Unix3Unix3
Unix3
 
Unix2
Unix2Unix2
Unix2
 
Unix1
Unix1Unix1
Unix1
 

Tdd

  • 1. 今日から始めるTDD on Rails 東京大学文学部 3年 Takaya Kotohata t.kotohata@gmail.com 12年12月25日火曜日
  • 2. 自己紹介 • twitter @tii_kot • blog http://tkot.hatenablog.com/ • github https://github.com/mhersmh • Rails歴1.5年 • 最近はNode.jsとかErlangに注目してます 12年12月25日火曜日
  • 3. テストは書かなきゃいけないの? • 書きましょう • 書くことで得られる知識は意外と広いので純粋に勉強になる • 慣れればブラウザをリロードが馬鹿らしくなる • デプロイ後のアプリケーションの可用性を高める • 継続的デリバリー 12年12月25日火曜日
  • 4. 逆に書かなくてもよいケースとは? • 金銭や人命にかかわらないアプリであること • Railsの基本的機能しか使っていないこと • とりあえず動いてます的なプロトタイプで十分なこと • 保守・運用の予定がないこと 確かに上記をすべて満たせば書く必要はないか もしれない。 12年12月25日火曜日
  • 5. Railsでよく使われるテストフレームワーク • Test::Unit Ruby標準ライブラリ。 • shoulda Test::UnitをRSpec風に拡張してくれる。 • RSpec 一番人気。 • Cucumber 自然言語でシナリオを書いて、対応するユーザやアプリの動きを Rubyのコードで書く受け入れテスト DHHはTest::Unit派。それぞれ得意不得意があるのでプロ ジェクトごとにベストなものを選べばよいが、迷ったら RSpecを使えば間違いない 12年12月25日火曜日
  • 6. RSpecとCucumberの組み合わせ • かなりメジャーな組み合わせ • Cucumberは自然言語で書かれたユーザストーリーをfeatureとして定義、開発 者以外も読むことができるのが利点とされる • とはいえ本当に開発者以外が読むの? • RSpecとCucumberで異なるDSLを学習するコストがかかるので、RSpec一本 でもいいような気がする。 • だけど今日はCucumberも勉強します笑 12年12月25日火曜日
  • 7. 基本的なTDDの流れ ①要件定義・設計 ②受け入れテスト作成 ③設計・ユニットテスト ④コーディング ⑤リファクタリング 12年12月25日火曜日
  • 8. 各フローのアクション • 要件定義・設計・・・アプリケーションにどのような機能が必要か、どのよ うに画面は遷移するかなどを洗い出す。各リソースにどのような仕事分担をさ せるかなども考えるとよい • 受け入れテスト・・・これにパスしたら要件が満たされているというテス ト。ユーザーストーリーに対応し、ユーザの挙動をシミュレートするテストに なる。CucumberあるいはRequest Specに対応する。 • 設計・ユニットテスト・・・最小単位で戻り値のオブジェクト型や必要なイ ンターフェースを設計・定義する • コーディング・・・ユニットテストをパスする最低限のコードをひとまず書 き上げる 12年12月25日火曜日
  • 9. よくある誤解 • アジャイル開発は設計を厳格に定義せずにとりあえずコードを書いてみる手 法だなんていう風に思ってるかもしれませんがそれは全く誤解です • Railsは最初のリソース設計でコケると先ほどの開発フローチャートをすべて やり直すことになる! 一つのイテレーションにおける要件定義と設計、画面 遷移のイメージ確認などは十分時間をかけるべき • ドキュメントを書かないなんていうのも全く誤り。ドキュメント主体になら ないというだけで、設計について話しあったり将来的に追加されそうな機能 は積極的にメモを残すべきだし、なるべくドキュメントも同一のバージョン 管理下に置いたほうがいい。 12年12月25日火曜日
  • 10. テストは完璧とは限らない • テストフレームワークに慣れてないうちはむしろテストの書き間違いのほうが 圧倒的に多い • 受け入れテストの変更はイコール仕様変更なので問題ないが、ユニットテス トの変更は設計の変更レベルであり得て、しかもリファクタリング中に起こ りうる • そのため、「③で理想的設計を定義し、④から⑤に移行して終了」という流 れがベストでも、「⑤から③に立ち戻る」というケースも多い。現実的に ③④⑤はグルグル回るが、やはり最終的にユニットテストをコードが通過して いればよい。 12年12月25日火曜日
  • 11. 受け入れテスト・ユニットテストとは何か • 受け入れ(acceptance)テスト=このテストを通過すればストーリーを満たして いると考えて良いテストのこと。「ユーザーがXXにアクセスして、idに⃝⃝、 passwordに⃝⃝を入力してregisterボタンを押すと∼∼が行われる」のように 実際の操作に近いテスト。 • ユニット(単体)テスト=オブジェクトの振る舞いが期待されたもの通りかを検 証する。たとえばMyObj#to_sメソッドはStringのインスタンスを返すこと を、いくつかのMyObjインスタンスに対してチェックする、など。 12年12月25日火曜日
  • 12. よくある誤解2 • ×ユニットテストはModelのテストのこと・・・Controllerでレスポンスが xx_pathにリダイレクトされる、などもユニットテストといえる。 • ×ユニットテストはホワイトボックステストである・・・ホワイト~, ブラック ~は次元の異なる概念。プログラム構造に対して網羅的となるテストがホワイ トボックステストで、メソッド内の実装に踏み込まないテストがブラック ボックステスト。 12年12月25日火曜日
  • 13. ユニットテスト(続き) • プログラムを利用する場合は、各オブジェクトにメッセージを送ってやり取 りをするルーティンのほうに関心があるから、オブジェクトがすべき仕事を 記述するユニットテストがTDD初心者には分かりにくい。 具体例 UsersController#createをルーティン class UsersController < ApplicationController で考えると、@user.saveでDBに保 def create 存されるかどうかに関心を持ってし @user = User.new(params[:user]) まうが、DBに保存されるかどうか if @user.save redirect_to user_path(@user) はModelの仕事であるから、 else Controllerは単に@user.saveがtrueを render :new 返したらuser_pathにリダイレクト end end し、そうでないならnewをrenderす end ることに注力すればよい 12年12月25日火曜日
  • 14. テストファーストの最大の利点 • テストを全く書かない場合、人間の思考はオブジェクトやメソッドがある実 行コンテキストでどのような仕事をするかに集中しがち。 • ユニットテストから書くことで各オブジェクトの仕事や領域、インターフェー スが明確となって疎結合なコードを書くことができる • 受け入れテストから書くことで実装の可否の基準が明確になる=仕様書を書 くコストを別の資産に転換できる 12年12月25日火曜日
  • 15. Cucumber(1) • Railsほど厳格な規約はないものの、例えばUserというリソースに対するテス トならfeatures/users/registration.featureのようにまとめると便利 • 自然言語で書かれたfeatureと、その内容をコードの動作に解釈する step_definitionsが存在 • features/step_definitions/user_steps.rbにUserのstepをまとめると良い • step_definitions内で使われるfill_inやclick_buttonなどのメソッドはwebratが提 供するもの。 12年12月25日火曜日
  • 16. cucumber(2) ⃝features/users/registration.feature (フィーチャー定義) もし メールアドレスはuser@example.com,パスワードはtesttest,ユーザ名はuser1で ユーザ登録をする ⃝features/step_definitions/user_steps.rb(ステップ定義) When /^メールアドレスは(.*),パスワードは(.*),ユーザ名は(.*)でユーザ登録をする$/ do | email, password, name|  visit new_user_registration_path  fill_in(“user_email”, with:email)  fill_in(“user_password”, with: password)  fill_in(“user_password_confirmation”, with: password)  fill_in(“user_display_name”, with:name)  click_button(“Sign up”) end 12年12月25日火曜日
  • 17. cucumber(3) • Cucumberのstep_definitionsで書かれるコードはDBにレコードを投入するも のと、ブラウザの動きをシミュレートものの2種類が大半 • 前者はもちろんActiveRecordなどのDSLが使用可能だが、後者はwebratある いはcapybaraが提供するメソッドを覚える必要がある(10~20種類くらい) • 現在は廃止されたが少し前までwebrat_ja_steps.rbなどの汎用的ステップ定義 が提供されていた • 廃止されたのはフィーチャー定義が冗長になる原因だったから。 12年12月25日火曜日
  • 18. webrat_ja_steps.rb #coding: utf-8 When /^”(.*)”ボタンをクリックする$/ do |button| click_button(button) end When /^”(.*)”リンクをクリックする$/ do |link| click_link(link) end When /再読み込みする/ do visit request.request_uri end When /^”(.*)”に”(.*)”と入力する$/ do |field, value| fill_in(field, with: value) end などなど... 12年12月25日火曜日
  • 19. Cucumber(4) シナリオ: 登録されていないmailとパスワードで新規登録  もし “ユーザ登録ページ”へアクセス  かつ “user_email”に”user1@example.com”と入力する  かつ “user_password”に”testtest”と入力する  かつ “user_display_name”に”user1”と入力する  かつ “user_password_confirmation”に”testtest”と入力する  かつ “Sign up”ボタンをクリックする  ならば “You have signed up successfully.”と表示されていること 冗長でわかりづらいし、再利用性に乏しい (3つ前のスライドと比べてみよう) 12年12月25日火曜日
  • 20. Cucumber(5) • featureに対して正規表現でマッチしたstepが呼び出される=2つ以上にマッチ してしまうとエラーになるので注意。曖昧なstepは書かない。 • 引用符付きのstepとそうでないものがあるが、基本的には単なる文字列の一 部なので好みの問題。囲ったほうが変数がわかりやすいかも。 • stepの中で別のstepを再利用したり、tableでレコードを一度に登録するなど ができます。覚えてください。 12年12月25日火曜日
  • 21. RSpec (1) • Cucumberがアプリケーションの仕様であるのに対して、RSpecはプログラム の仕様と考えるとわかりやすい • モジュールやクラスがどのようなメソッドを持って、そのメソッドはある引数 に対してどのような結果を返すのか、などのプログラムレベルでのテスト • 最小レベルのテストで、対象の振る舞いだけに集中することが重要。例えば あるクラスをテストするときに他のクラスに処理を委譲する箇所があったと して、そちらの実装を気にせずにテストするためにオブジェクトやメソッド を偽物(Fake)化する、など 12年12月25日火曜日
  • 22. RSpec(2) • RSpecはRailsに限定されたものではない。Railsで使う場合以下のようなテス トディレクトリが存在。(1)spec/controllers (2)spec/models (3)spec/helpers (4)spec/views (5)spec/libs (6)spec/routing (7)spec/requests (8)spec/support • requestはwebratなどを使用した受け入れテスト。Cucumberを使う場合はか ぶるので要らないと思う。 • routingはconfig/routes.rbとイメージしているURLが合致しているかをテスト するだけなのでカバレッジを気にしないなら不要かも。 • viewも頻繁に書き換わるところなので、書く必要はないかもしれない。 12年12月25日火曜日
  • 23. RSpec(3) • 逆に書くべきなのはspec/models, spec/controllers, spec/libs, spec/helpers。 • Controllerのspecでは、あるルーティングにHTTPリクエストを飛ばした時に 想定しているオブジェクトに想定しているメッセージを送っているかを検証 =モデルの適切なメソッドを(適切な引数で)呼び出しているか、responseに flashは含まれるか、想定しているURLにリダイレクトしているか、などをテス トする • Modelのspecでは、定義したメソッドが正しい挙動をしているか、実際に メッセージを送って戻り値を検証するのがメイン。例外の発生やファイルが 作成されるかなども検証できる。 12年12月25日火曜日
  • 24. RSpec(4) describe UsersController do ※stub(:save).and_return(false) describe “POST create” do 実際にsaveされるかはここでテスト describe “with invalid params” do しない。偽のメソッドによってfalse it “re-render the ‘new’ template” do を返させる。 User.any_instance.stub(:save).and_return(false) post :create, {user: {name: “test”}} response.should render_template(“new”) ※should テストの核の部分。これを end エクスペクテーションとかアサー end end ションと言う。 end 12年12月25日火曜日
  • 25. RSpec(5) • 各種のマッチャを覚える必要がある。 • 基本的にはitブロックの中に1つのエクスペクテーションを書く。 • エクスペクテーションごとに共通化できる処理はメソッドにして呼び出す か、beforeにまとめるなどが可能 • describe(context)は各テストをグルーピングできる。グルーピングによってテ ストケースがわかりやすくなるほか、before/afterなどのフックをグループご とに定義可能になってうれしい。 12年12月25日火曜日
  • 26. RSpec(6) • スタブとモックは本物の代用となるコード。 • スタブはインターフェースを提供するが、モックはエクスペクテーションも提 供する。 • つまり以下のコードで下は@user.nameが呼ばれないとテストが通らない。 @user.stub(:name).and_return(“hogehoge”)     スタブ @user.should_receive(:name).and_return(“hogehoge”)   モック 12年12月25日火曜日
  • 27. RSpec(7) • double,mock,stubの概念とRSpecにおける語用には隔たりがあるので注意。 RSpecが提供するmock(Obj)とstub(Obj)はdouble(Obj)のエイリアスである。 • rspec-railsが提供するmock_modelとstub_modelという拡張がある。例えば form_forヘルパーに対してどのように応答するオブジェクトを渡すべきか知ら ずに済ませたい=>mock_modelを使えばActiveRecordオブジェクトの基本的 な応答をスタブ化できる • mock_modelとstub_modelの違い=>stub_modelは実際のActiveRecordオブ ジェクトを作成する。ただしDBとのやり取りを行わない(saveや update_attributesを呼び出すとエラーになる) 12年12月25日火曜日
  • 28. TDD実践編 今回作るアプリケーション • Twitterのようなアプリケーションを作りましょう • 認証(devise)を含むテストも書いてみます • デザインは作る気はないので、flash[:info]やi18nなどはかなり適当にやります • https://github.com/t-kot/tdd_on_rails 12年12月25日火曜日