• Save
継続的8章
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

継続的8章

on

  • 667 views

 

Statistics

Views

Total Views
667
Views on SlideShare
667
Embed Views
0

Actions

Likes
0
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

継続的8章 Presentation Transcript

  • 1. 継続的デリバリー8章
  • 2. 8.1  導入 •  内容   –  自動受け入れテストはどのようなものなのか   –  デプロイメント内でどう位置づけられるのか
  • 3. 8.1  導入 •  基本的なCIとCDの違いは、受け入れテストス テージ以降があるかどうからしい。  •  受け入れテストは機能テストやユニットテスト と比べて何が違うのか?   –  ストーリー・要件の受け入れ基準が満たされてい るかを検証する   –  ビジネス視点でのテスト   –  顧客が意図したことを実行できていることを証明  
  • 4. 8.2  なぜ自動受け入れテストが   欠かせないのか? •  Q. 自動受け入れテスト、作成と保守のコスト が高いのではないか?  •  A. 上手くやらないとそうなる
  • 5. 8.2  なぜ自動受け入れテストが   欠かせないのか? •  Q. 十分なカバレッジのunit  testで事足りるは ずだ  •  A. unit  test  や  component  test  をしっかり やっても検出できない問題があり、それを受 け入れテストで検出できる
  • 6. 8.2  なぜ自動受け入れテストが   欠かせないのか? •  Q. 手作業でやればいい  •  A. 自動化したほうが安上がりである
  • 7. 受け入れテストが得意なこと •  ユーザーシナリオのテスト   –  シナリオにおいてたどる状態の欠陥は  unit  test   では検知できない  •  スレッドの問題を検出することもある  •  イベント駆動アプリケーションでの突発的な振 る舞いの検出  •  環境や設定ファイルに起因する問題の検出  •  大規模な変更に対するアプリケーションの保 護  
  • 8. 自動受け入れテストのコストに対する メリット •  フィードバックループの短縮   –  修正が容易なうちに欠陥を発見できる  •  テスター・開発者・顧客の協力の強制   –  皆が協力するようになる   –  皆がビジネス価値に集中する  •  良い設計の強制   –  薄いUIレイヤ   –  本番環境と開発環境で同じように実行できる設 計
  • 9. 8.2.1  保守しやすい   受け入れテストスイートの作り方 •  受け入れ基準を分析   –  ユーザーにとって価値があり、テスト可能  •  受け入れテストをレイヤ化する  
  • 10. GUIを叩いてテストする? •  テストが壊れやすくなる   –  GUIは頻繁に変更されるため  •  シナリオのセットアップが煩雑になる  •  GUIの作りによってはそもそもテストできない ことも
  • 11. GUIを叩かずテストする? •  上手く設計する   –  プレゼンテーションレイヤにビジネスロジックを含 まない   –  プレゼンテーションレイヤはお絵かきに徹する  •  筆者おすすめの方法
  • 12. 上手くない設計のアプリケーションは   どうやってテストする? •  GUIを叩いてテストするしか無い   –  ウィンドウドライバパターンを使って乗り越える
  • 13. 受け入れテストのレイヤ 受け入れ基準   Cucumber   Given…   FitNesse   When…   …   Then… 実装レイヤ     ドメインの言語を使う   UIの要素を参照しない   アプリケーションドライバレイヤ     ウィンドウドライバを含む 特定のアクションを実行して   結果を返すために、アプリケーションと   どうやってやり取りすべきか理解している  
  • 14. 受け入れ基準レイヤ シナリオ: ユーザーの注文を口座から          正しく引き落とさなければならない      前提 ボンドという名前の証券がある    かつ デイブというユーザーがいて、口座に50ドルある    もし デイブの名義でログインする    かつ ボンドという名前の証券を選択する    かつ 4口買うことにして、それぞれ10ドルである    かつ その注文が上手くいった    ならば 口座に10ドル残る  
  • 15. 実装レイヤ require  ‘applicaDon_driver/admin_api’  require  ‘applicaDon_driver/trading_ui’    …    given  /^(w+)という名前の証券がある$/  do  |instrument|      @admin_api.create_instrument(instrument)  end    given  /^(w+)という名前のユーザーがいて、口座に(w+)ドルある$/  do  |user,  amount|      @admin_api.create_user(user,  amount)  end    when  /^(w+)の名義でログインする $/  do  |user|      @trading_ui.login(user)  end    …    
  • 16. アプリケーションドライバレイヤを上手く定義すると、   受け入れ基準をテストの実装で表現できる xUnit  などの   Unit  test  framework   受け入れ基準 兼 実装レイヤ   アプリケーションドライバレイヤ     ウィンドウドライバを含む 特定のアクションを実行して   結果を返すために、アプリケーションと   どうやってやり取りすべきか理解している  
  • 17. 実装レイヤ public  class  PlacingAnOrderAcceptanceTest  extends  DSLTestCase  {    @Test    public  void  userOrderShouldDebitAccountCorrectly(){      adminAPI.createInstrument(“name:    bond”);      adminAPI.createUser(“Dave”,  “balance:    50.00”);      tradingUI.login(“Dave”);        tradingUI.selectInstrument(“bond”);      tradingUI.placeOrder(“price:    10.00”,  “quanDty:  4”);      tradingUI.confirmOrderSuccess(“instrument:    bond”,  “price:    10.00”,  “quanDty:    4”);        tradingUI.confirmBalance(“balance:  10.00”);    }  }    
  • 18. 実装レイヤ ユーザー生成・登録や   証券生成は複雑な処理だが、   抽象化してシンプルに  public  class  PlacingAnOrderAcceptanceTest  extends  DSLTestCase  {    @Test   表現している  public  void  userOrderShouldDebitAccountCorrectly(){      adminAPI.createInstrument(“name:    bond”);      adminAPI.createUser(“Dave”,  “balance:    50.00”);      tradingUI.login(“Dave”);        tradingUI.selectInstrument(“bond”);      tradingUI.placeOrder(“price:    10.00”,  “quanDty:  4”);      tradingUI.confirmOrderSuccess(“instrument:    bond”,  “price:    10.00”,  “quanDty:    4”);        tradingUI.confirmBalance(“balance:  10.00”);    }  }    
  • 19. 実装レイヤ public  class  PlacingAnOrderAcceptanceTest  extends  DSLTestCase  {    @Test   非同期処理をアプリケーションドライ  public  void  userOrderShouldDebitAccountCorrectly(){   バレイヤに押しこむことで、      adminAPI.createInstrument(“name:    bond”);     再利用可能・修正容易・最適化容易  adminAPI.createUser(“Dave”,  “balance:    50.00”);      tradingUI.login(“Dave”);   になる      tradingUI.selectInstrument(“bond”);      tradingUI.placeOrder(“price:    10.00”,  “quanDty:  4”);      tradingUI.confirmOrderSuccess(“instrument:    bond”,  “price:    10.00”,  “quanDty:    4”);        tradingUI.confirmBalance(“balance:  10.00”);    }  }    
  • 20. アンチパターン •  実装レイヤでアプリケーションとのやり取りの 詳細を記述してしまう   –  (例)アプリケーションのAPIやUIを直接参照する   –  (結果)APIやUIの変更でテストスイートが崩壊   –  (解法)やり取りの詳細をアプリケーションドライバ レイヤの責務とする
  • 21. 8.3  受け入れテストを作成する •  この節では、自動受け入れテストをどのよう に作るべきかについて議論する
  • 22. 8.3.1  アナリストとテスターの役割 •  チームに一人、ビジネスアナリストがいるべき  •  ビジネスアナリストの役割   –  顧客やユーザーの代表になる   •  顧客と協力して、   –  要件を識別   –  優先順位付け   •  開発者と協力して、   –  開発者がユーザー視点でアプリケーションを理解できるようにす る   •  テスターと協力して、   –  受け入れ基準が適切か確認   –  機能が受け入れ基準を満たしているか確認
  • 23. 8.3.1  アナリストとテスターの役割 •  テスターはどんなプロジェクトにも欠かせない  •  テスターの役割   –  ソフトウェアの品質がどうなっているのか、リリー スする準備がどの程度できているのかについて、 顧客を含むデリバリーチーム全員に理解させる   •  受け入れ基準の定義  with  顧客  and  アナリスト   •  自動受け入れテスト作成  with  開発者   •  探索的テスト   •  ショーケース
  • 24. 8.3.1  アナリストとテスターの役割 •  誰かに専念させる必要はない   –  開発者兼アナリスト   –  アナリスト兼テスター  •  役割を果たす人が常にチームに居ることが重 要
  • 25. 8.3.2  イテレーティブな   プロジェクトにおける分析 •  この節では、開発プロセスにイテレーティブな ものを使用していることを前提とする
  • 26. 開発者 アナリスト テスター 顧客
  • 27. イテレーションにおける役割 受け入れ基準   テスターによる   要件実装   定義 テスト   短い   デモ   キックオフミーティング  
  • 28. 受け入れ基準定義 •  アナリスト   –  定義にほとんどの時間を使う   •  これによってチームが「Done」を判断でき るようになる   –  テスターや顧客と密接に協力   •  完了を定義するために測定するべきもの を、テスターの経験から伝えてもらえる   •  要件の本質をテスターに伝えることができ、 要件のテストに役立ててもらえる
  • 29. 短いキックオフミーティング •  要件が実装される直前に行う   •  アナリストの役割   –  要件とその文脈、受け入れ基準を示 す   •  テスターと開発者の役割   –  一緒に作業し、自動受け入れテスト 一式について合意する   •  可能であれば顧客も参加  
  • 30. 短いキックオフミーティング •  効能   –  アナリスト   •  実装やテストのコストが高い要件を作っ てしまうことを回避できる   –  テスター   •  システムを誤解して、欠陥でないものを 欠陥として捉えてしまうことを防げる   –  開発者   •  関係ないものを実装してしまうことを避 けられる  
  • 31. 要件実装 •  開発者   –  アナリストに相談する   •  要件のよくわからない箇所   •  要件の問題   •  要件が解決する問題に対する、効率的 な他の解決方法の提案  •  デプロイメントパイプラインによって、 こうしたやり取りが促進される  
  • 32. デモ •  開発者が作業を完了した後で行わ れる   –  完了:=  ユニットテスト、コンポネントテ スト、受け入れテストが通ったという こと  •  開発者   –  アナリスト、テスター、顧客の前でデ モをする  
  • 33. デモ •  意図したとおりに要件が実現され ていることを確認する機会  •  細かい問題が指摘されることも多 い   –  CDをやっているならばすぐに対応で きるはず・・・   –  代替案の議論や変更のきっかけとな る  •  システムの進化の方向性について、 チームで理解を共有する機会  
  • 34. テスターによるテスト •  デモの後は、テスターによってテス トされる  
  • 35. 8.3.3  実行可能な仕様としての   受け入れ基準 •  振る舞い駆動開発の考え方   –  受け入れ基準はアプリケーションの振る舞いに対 する顧客の期待という形で書かれるべき   –  受け入れテストは実行可能な仕様   •  仕様の陳腐化を防ぐ
  • 36. 8.4  アプリケーションドライバレイヤ •  テスト対象のシステムとどのようにやり取りす るかを理解しているレイヤ  •  APIがドメインの言語で表現される   –  DSLと考えることが出来る   –  この場合、ドメインはアプリケーションの仕様 受け入れ基準   実装レイヤ   アプリケーションドライバレイヤ  
  • 37. 8.4.1  受け入れ基準の表現方法 •  外部DSLを使う場合(Cucumber  など)   –  メリット   •  受け入れ基準がそのまま実行可能な仕様となる   –  デメリット   •  実装との同期のオーバーヘッド  •  内部DSLを使う場合(xUnit  など)   –  メリット   •  複雑なツールを使わない   •  開発環境の自動補完が使える   –  デメリット   •  ドキュメント(受け入れ基準)生成が面倒   –  xUnit  テストケースからフィーチャーやストーリー、ステップをドキュメント として生成するのは難しい
  • 38. 8.4.2  ウィンドウドライバパターン:   テストとGUIを疎結合にする •  アプリケーションドライバのサブセット  •  GUIとやりとりする  •  抽象レイヤを導入し、受け入れテストとテスト 対象システムの結合度を減らす   –  GUIの変更がテストに及ぼす影響を減らしている  •  あらゆるテストはこのレイヤを介してのみUIと やりとりする
  • 39. 8.4.2  ウィンドウドライバパターン:   テストとGUIを疎結合にする •  GUIの各部分に対して対応するデバイスドラ イバを書かなければならない Test  Suite  A Test  Suite  B Test  Suite  C ドライバ1 ドライバ1 ドライバ1
  • 40. レイヤリングなしの場合 @Test  Public  void  shouldDeductPaymentFromAccountBalance()  {    //  ログイン処理    selectURL(“hjp://my.test.bank.url”);    enterText(“userNameFieldID”,  “testUserName”);    enterText(“passwordFieldID”,  “testUserName”);    click(“loginBujonId”);    waitForResponse(“loginSuccessIndicator”);      //  支払い処理    …      //    asserDons    …  }    
  • 41. レイヤリングした場合 @Test  Public  void  shouldDeductPaymentFromAccountBalance()  {    AccountPanelDriver  accountPanel  =  new  AccountPanelDriver(testContext);      //  ログイン処理 <-­‐  このコメントが不要となる    accountPanel.login(“testUserName”,  “testPassword”);    accountPanel.assertLoginSucceeded();      //  ステップごとにアサーションを入れても、                      //  テストの意図がぼやけない。                      //  Fail-­‐fast  が実現された        //  支払い処理    …      //    asserDons    …  }    
  • 42. 8.5  受け入れテストを実装する •  レイヤリングして終わりと思ったら大間違い  •  受け入れテストでは、   –  特定の状態にセットアップし、   –  幾つかのアクションを実行し、   –  結果を検証する  •  テストを不安定にさせない   –  非同期処理とタイムアウトを制御   –  データセットを慎重に管理   –  外部システムとの統合をシミュレート  
  • 43. 8.5.1  受け入れテストにおける状態 •  システムとやり取りをするので、状態は必須   –  振る舞いをテストするには、特定の開始状態にい なければならない  •  複雑な状態にテストが依存することを最小限 に抑える
  • 44. 複雑な状態にテストが依存することを 最小限に抑える •  プロダクションデータのダンプを受け入れテス トのデータベースに入れてはならない(キャパ シティテストは例外)  •  統制のとれた最小限のデータセットを保守す る   –  正しく動くとわかっている開始地点を確立   •  データセットをスクリプトとしてバージョン管理   •  アプリケーションの公開APIを用いてセットアップ(12章)
  • 45. テストはアトミックであるべき •  実行順序に依存しない   –  追跡が難しいバグを生み出す原因が排除される   –  並列実行が可能となる
  • 46. アトミックなテスト •  必要な物は全て自分で生成  •  成功・失敗の記録以外に痕跡を残さない  
  • 47. アトミックなテストへのアプローチ •  アプリケーションの機能によってスコープを区 切る   –  テスト開始時に新しいアカウントを作る   –  アプリケーションドライバで、新しいアカウントをシ ンプルに作成できる基盤を作る
  • 48. テストケース間で   状態を共有する場合 •  そうせざるをえない事もある  •  注意深く設計すること   –  テストが脆くなりがち   –  DBにレコード4件書き込み、3番目を取り出す場 合、テストの前に垂れもレコードを追加しないよう にしなければならない  
  • 49. 開始状態を保証できない場合 •  そういうこともある  •  テストを防御的に作ること   –  テスト開始時に状態が期待通りか確かめる   •  Fail-­‐fast   –  相対的な観点からテストする   •  ×  array.push(‘a’)            array.size.should  be  1   –  テスト開始時に  array  が空であることを保証できない   •  ○  expect{  array.push(‘a’)  }.to  change  {  array.size  }.by(1)  
  • 50. 8.5.2     プロセス境界・カプセル化・テスト •  素直なテストを書かねばならない   –  特権的なアクセスを要求しない  •  テストしやすくするために設計アプローチを変 える必要が出てくる   –  × バックドアを作る   •  カプセル化が破壊される   –  リファクタリングを妨げる   –  テストが壊れやすくなる   –  ○ コードをより良くモジュール化し、より良くカプ セル化する
  • 51. バックドアが避けられない場合 •  本当にバックドアしか手がない時のみバックド アを使う   –  外部コンポネントとやり取りするコードを  Test   Double  で置き換える   –  テスト用外部コンポネントを作る  •  バックドアは整備・維持に手がかかるので、 最後の手段にする
  • 52. 8.5.3  非同期とタイムアウトを管理する •  非同期システムのテストには、非同期特有の 問題がある   –  ユニットテストでは非同期処理を避けるべき   •  テストが不安定になる   –  受け入れテストでは非同期処理が避けられない ことがある   •  スレッドやトランザクション
  • 53. 非同期システムのテスト   特有の問題 •  問題   –  テストが失敗したのか、あるいは結果を待ってい るだけなのかわからない  •  対策   –  問題を隔離する  :=  非同期処理を同期呼び出しの 背後に隠蔽する
  • 54. 例:ファイル受信箱システム •  受信箱(ファイルシステム上の、とあるディレ クトリ)をポーリングして、ファイルの収集と ファイルが届いたことをメールで通知するシス テム
  • 55. ファイル受信箱システムの   ユニットテスト •  コンポネントを別々にテストする   –  テストダブルを使ってテスト対象を切り出せる   •  ファイルシステムをシミュレートする   •  時計の偽物を作る
  • 56. ファイル受信箱システムの   受け入れテスト •  ユニットテストよりも更に踏み込んだテストを しなければならない   –  デプロイメントが上手く行ったことをテスト   –  ポーリングの仕組みが設定できたことをテスト   –  メールサーバーが正しく設定されたことをテスト   –  全てが協調して動作することをテスト
  • 57. ファイル受信箱システムの   受け入れテスト •  ここで問題となるのが以下の2つ   –  ポーリングの間隔   –  Eメールが届くまでの時間
  • 58. 理想的なテスト public  void  ShouldSendEmailOnFileReceipt()  {    ClearAllFilesFromInbox();    DropFileToInbox();    ConfirmEmailWasReceived();  }     シンプルで明確  
  • 59. 誤ったテストの実装:   メールが届く前にアサート private  void  ConfirmEmailWasRecieved()  {    if(!EmailFound())  {      Fail(“メールを受け取れなかった”);    }  }   テストは失敗するが、     問題はプロダクトコードではなく   テストコードにある  
  • 60. 正しいテストの実装:   待つ private  void  ConfirmEmailWasRecieved()  {    Wait(DELAY_PERIOD);      if(!EmailFound())  {      Fail(“時間内にメールを受け取れなかった”);    }  }     十分待てば、   妥当なテストとなる  
  • 61. 欠点と対策 •  欠点   –  待ち時間が容易に積み上がってしまう  •  対策   –  結果のポーリング   –  媒介となるイベントを監視
  • 62. 結果のポーリング private  void  ConfirmEmailWasRecieved()  {    TimeStamp  testStart  =  TimeStamp.NOW;    do  {      if(EmailFound())  {        return;      }      Wait(SMALL_PAUSE);    }  while(TimeStamp.NOW  <  testStart  +  DELAY_PERIOD);    Fail(“時間内にメールを受け取れなかった”);  }    
  • 63. 媒介となるイベントを監視 •  受信したEメールの処理を行なってくれるサー ビスがある場合に使える方法   –  Eメールが届くと、それに対応してイベントを生成   –  このイベントを待つことで、テストを高速化する
  • 64. イベント監視 private  void  ConfirmEmailWasRecieved()  {    TimeStamp  testStart  =  TimeStamp.NOW;    do  {      if(EmailFound())  {        return;      }      Wait(SMALL_PAUSE);    }  while(TimeStamp.NOW  <  testStart  +  DELAY_PERIOD);    Fail(“時間内にメールを受け取れなかった”);  }    
  • 65. イベント監視 private  boolean  emailWasReceived  =  false;    private  boolean  EmailFound()  {    return  emailWasReceived;  }    public  void  EmailEventHandler(…)  {    emailWasReceived  =  true;  }   高速化という観点で、意味があるのか?   メールが大量に溜まっている場合には効果あり?  
  • 66. •  ConfirmEmailWasReceived  のクライアントに とって、このメソッドは同期的であるように見 える   –  抽象度の高いテストがシンプルに書ける   –  この種のコードはアプリケーションドライバレイヤ に置いて、再利用すべき   •  効率的で、信頼できる非同期処理の再利用
  • 67. 8.5.4  テストダブルを利用する •  自動受け入れテストとユーザー受け入れテス トは違う   –  自動受け入れテストは外部システムと統合された 環境で実行してはならない   •  制御可能な環境を提供しなければならない   –  制御可能  :=  テスト用初期状態を正しく作れる
  • 68. 受け入れテストの矛盾 •  我々の目標(受け入れテストの?CDの?)は、 システムを継続的に統合し、問題を早期に発 見することである   –  外部システムと統合するべきということ  •  受け入れテストでは、外部の依存対象による 影響を最小限に抑えなければならない   –  外部システムと統合するべきでないということ  
  • 69. 外部システムと統合してしまうことの   問題点 •  受け入れテストのスコープに外部システムを 含めてしまうと、システムやその初期状態を 制御しにくくなる  •  外部システムに重大な負荷がかかる可能性
  • 70. 妥協 •  外部システムを表現したコンポネントを作成 する   –  外部システム1つに対して1コンポネント   –  外部システムのインターフェイスを表現  •  このコンポネントを、   –  自システムとのやり取りという観点   –  外部システムとの通信地点という観点  •  の両方から保証する
  • 71. 自システムとのやり取りの観点   から保証 設定   外部システムに対する   ファイル 外部システムに対する  ローカルインターフェース ローカルインターフェース 外部システムを  外部システムとのやり取り   シミュレートする  (ゲートウェイ、アダプタ) Test  Double 外部システムとの通信を表現する   Test  Double  を作成する 外部システム
  • 72. 外部システムとの通信地点という観点   から保証 外部システムに対する   ローカルインターフェース •  インテグレーションテスト   –  統合点の周りに小粒のテスト スイートを作成   外部システムとのやり取り   –  実際に外部システムと統合し (ゲートウェイ、アダプタ) てテストを実行する 外部システム
  • 73. 外部システムとの通信を表現する   Test  Double  を作成する •  メリット   –  テストの開始地点を構築できる   –  通信失敗のシミュレーション   –  エラーが返された時のシミュレーション   –  高負荷の場合のレスポンスのシミュレーション
  • 74. インテグレーションテスト:   外部システムとの統合ポイントをテストする •  外部システムとの接点は問題がよく起きる   –  自システムと外部システムとで共有するデータ構造   –  通信の頻度   –  宛先解決の仕組みの設定   –  外部システムの変更  •  インテグレーションテストでは、こうした問題に 集中しなければならない
  • 75. インテグレーションテスト •  外部システムが開発中の場合、インター フェースの性質が変化するのが普通   –  スキーマ   –  システム間の契約   –  情報の中身  •  どこで合流するかを見極めなければならない
  • 76. インテグレーションテスト •  著者の経験によると、ほとんどのインテグ レーションテストでシミュレートすべき明確な シナリオがいくつかある  •  そのようなシナリオは少数のテストで網羅す ることを勧める   –  この場合、カバレッジは完璧ではない   –  しかし、カバレッジを完璧にするのは難しく、費用 対効果が下がってゆく  
  • 77. インテグレーションテスト •  自システムと外部システムとのやり取りを網 羅するようスコープを定める   –  外部システムのインターフェイスを完全にテストし ようとしてはならない   –  141ページ「インテグレーションテスト」のガイドラ インに従う
  • 78. インテグレーションテスト •  インテグレーションテストの実行頻度   –  受け入れテストの度に実行   •  外部システムに負荷がかかってしまう   –  日に一度、あるいは週に一度   •  デプロイメントパイプラインの個別のステージとする   •  キャパシティテストステージの一部とする
  • 79. 8.6  受け入れテストステージ •  コミットテストを通過したビルド全てに対して実 行する  •  受け入れテストに失敗したビルドはデプロイし てはならない   –  受け入れテストは曖昧に扱ってはならない  
  • 80. 受け入れテストのカバレッジが   不十分な場合 •  以下の3つのどれかが起こってしまう   –  プロセスの最後、開発が完了したと思った頃にバ グが見つかり時間をとられる   –  手作業で受け入れテストやリグレッションテストを 行い、大量の時間とお金を取られる   –  品質の悪いソフトウェアをリリースする
  • 81. 自動受け入れテストは   やった方がいい •  極端に期間の短い、人数の少ないプロジェクトで、自動受 け入れテストの実装からプロジェクトを始めるのはやりす ぎ   –  CIプロセスのステージを1つだけにし、その中でエンドツーエン ドテストをした方がいい  •  しかし、規模が大きくなれば、自動受け入れテストの価値 はコストに見合う  •  巨大なプロジェクトも小さいプロジェクトとしてスタートを切 る  •  プロジェクトが大きくなると、包括的な自動受け入れテスト を作るのは難しい  •  よってどんなプロジェクトでも自動受け入れテストはやった 方がいい
  • 82. 8.6.1  受け入れテストを   グリーンに保つ •  受け入れテストが壊れた場合、チームは手を 止めて、問題の仕分けを行う必要がある   –  テストが不安定なのか   –  環境の設定が問題なのか   –  アプリケーションが変更され前提が変わったのか   –  本物の失敗なのか  •  誰かが直ちに対応し、テストが通るようにしな ければならない
  • 83. 通らないテストを放置すると   どうなるか •  リリースが近づくにつれ、品質を保証するために、 受け入れテストをグリーンにしようとする  •  その頃には、受け入れテストの失敗の原因を特 定するのが難しくなっている  •  時間がないので、テストが削除されたり無視され る  •  結果、作業の見積りができず、コードが実際どう なっているのかわからないという状況に陥る  
  • 84. 犯人と思しき人物を特定せよ •  受け入れテスト失敗の原因特定は、ユニット テストほど容易ではない   –  ユニットテストの場合、チェックインした人が犯人   –  受け入れテストの場合、テストの合間に複数コ ミットされる可能性がある  •  どの変更に紐付いて受け入れテストが実行さ れたかを追跡できるようにしておくべき
  • 85. 受け入れテストは誰の所有物か? •  テストチームの所有物?   –  開発チームは受け入れテストへの影響を意識せ ずに変更を行なってしまう   –  テストチームが変更に気づくのは開発が終わった 後であり、その頃には開発者が別のタスクに取り 掛かっていて、テストチームはテストの修正と新 たなテストの実装で大変になる
  • 86. 受け入れテストは誰の所有物か? •  チーム全体の所有物   –  開発者が要件の受け入れ基準の実現に集中す るようになる   •  変更の影響を意識するようになる  
  • 87. 8.6.2  デプロイメントテスト •  受け入れテストは、本番環境にテスト環境を できるだけ近づけて実行する   –  資金が許すなら完全に同じであるべき   –  資金がないなら仮想化を行なって近づけるべき  •  受け入れ基準が満たされていることをテスト するとともに、擬似本番環境にデプロイできる ことをテストしている   –  デプロイメントがうまくいく事をテストする最初の 機会
  • 88. デプロイメントテスト •  デプロイメントテスト   –  基盤テストや環境テストと呼ばれるスモークテスト   •  環境が期待通りに設定されることをテスト   •  システムのコンポネント間の通信チャネルが正しく準 備され動作することをテスト   –  デプロイメントが成功したことを確認し、後に続く 機能的な受け入れテストのための開始地点を構 築することを目的としている
  • 89. 早めに失敗させる •  デプロイメントテストを特別なテストスイートと して扱う   –  デプロイメントテストが失敗したら、受け入れテス トステージを直ちに落とす   •  デプロイメントに失敗したら、当然受け入れテストも失 敗する   •  非同期システムのテストでは、失敗するテストで延々と 待機してしまう
  • 90. 8.7  受け入れテストのパフォーマンス •  受け入れテストでは、パフォーマンスは二の 次   –  実行時間について考える前に、システムや基盤 がデプロイされ、設定が完了し、起動及び終了が 出来ていなければならない  •  しかし、高速化するテクニックは数多くある
  • 91. 8.7.1  共通のタスクは   リファクタリングせよ •  テストの初期化を共通化する   –  受け入れテストはステートフル   –  受け入れテストは状態を共有しない   –  よってテストの事前条件への初期化のステップを 共通化する  •  共通化された初期化のステップを効率化する
  • 92. 共通のタスクはリファクタリングせよ •  初期化のステップで、UIを叩く代わりに公開 APIが使えるなら理想的  •  バックドアを使ってテストデータを設定するこ とが理にかなっていることもある   –  テストデータが普通に操作して設定できるデータ と異なっている場合もあるので注意しなければな らない
  • 93. 8.7.2  高価なリソースは共有せよ •  「適切な開始状態を作り出す」のを素直にや ろうとすると、テストはシンプルで信頼できる が、時間がかかってしまう   –  アプリケーションの起動、初期データの設定、状 態の初期化…  •  妥協し、高価なリソースを共有する   –  サーバーベースのアプリケーションなら、システ ム自体を共有できる
  • 94. 8.7.3  並列テスト •  テストを並列に実行する   –  マルチユーザーのサーバーベースシステムなら ばこれが適している   –  2つのテスト間で相互作用が発生するリスクがな いなら、単一のサーバーに対して2つのテストを 並列実行できる
  • 95. 8.7.4  コンピュートグリッドを用いる •  利用すべき場合   –  マルチユーザーでないシステム   –  高く付くテスト   –  同時並行でユーザーに使われることをシミュレー トするのが重要なテスト  •  いまどきのCIサーバーには、テストサーバー のグリッドを管理する機能がついている
  • 96. 8.8  まとめ •  受け入れテストによって、   –  チームメンバー全員が、ユーザーの求める価値に集中で きる   –  ソフトウェアが目的にかなっているという自信が増す   –  システムを大幅に変更してもリグレッションエラーを防ぐ防 衛策ができる   –  品質が大幅に改善される   –  欠陥がいつ発生しても、フィードバックが素早く得られるの で、直ちに修正できる   –  テスターの手が開くので、テスト戦略を考えたり、実行可 能な仕様を開発したり、探索的テストやユーザーテストを 実行できる   –  サイクルタイムを減少させ、継続的な開発を可能にする