SlideShare a Scribd company logo
1 of 96
継続的デリバリー8章
8.1	
  導入	
•  内容	
  
   –  自動受け入れテストはどのようなものなのか	
  
   –  デプロイメント内でどう位置づけられるのか
8.1	
  導入	
•  基本的なCIとCDの違いは、受け入れテストス
   テージ以降があるかどうからしい。	
  
•  受け入れテストは機能テストやユニットテスト
   と比べて何が違うのか?	
  
 –  ストーリー・要件の受け入れ基準が満たされてい
    るかを検証する	
  
 –  ビジネス視点でのテスト	
  
 –  顧客が意図したことを実行できていることを証明	
  
8.2	
  なぜ自動受け入れテストが	
  
          欠かせないのか?	
•  Q. 自動受け入れテスト、作成と保守のコスト
   が高いのではないか?	
  
•  A. 上手くやらないとそうなる
8.2	
  なぜ自動受け入れテストが	
  
             欠かせないのか?	
•  Q. 十分なカバレッジのunit	
  testで事足りるは
   ずだ	
  
•  A. unit	
  test	
  や	
  component	
  test	
  をしっかり
   やっても検出できない問題があり、それを受
   け入れテストで検出できる
8.2	
  なぜ自動受け入れテストが	
  
          欠かせないのか?	
•  Q. 手作業でやればいい	
  
•  A. 自動化したほうが安上がりである
受け入れテストが得意なこと	
•  ユーザーシナリオのテスト	
  
 –  シナリオにおいてたどる状態の欠陥は	
  unit	
  test	
  
    では検知できない	
  
•  スレッドの問題を検出することもある	
  
•  イベント駆動アプリケーションでの突発的な振
   る舞いの検出	
  
•  環境や設定ファイルに起因する問題の検出	
  
•  大規模な変更に対するアプリケーションの保
   護	
  
自動受け入れテストのコストに対する
      メリット	
•  フィードバックループの短縮	
  
 –  修正が容易なうちに欠陥を発見できる	
  
•  テスター・開発者・顧客の協力の強制	
  
 –  皆が協力するようになる	
  
 –  皆がビジネス価値に集中する	
  
•  良い設計の強制	
  
 –  薄いUIレイヤ	
  
 –  本番環境と開発環境で同じように実行できる設
    計
8.2.1	
  保守しやすい	
  
  受け入れテストスイートの作り方	
•  受け入れ基準を分析	
  
 –  ユーザーにとって価値があり、テスト可能	
  
•  受け入れテストをレイヤ化する	
  
GUIを叩いてテストする?	
•  テストが壊れやすくなる	
  
 –  GUIは頻繁に変更されるため	
  
•  シナリオのセットアップが煩雑になる	
  
•  GUIの作りによってはそもそもテストできない
   ことも
GUIを叩かずテストする?	
•  上手く設計する	
  
  –  プレゼンテーションレイヤにビジネスロジックを含
     まない	
  
  –  プレゼンテーションレイヤはお絵かきに徹する	
  
•  筆者おすすめの方法
上手くない設計のアプリケーションは	
  
   どうやってテストする?	
•  GUIを叩いてテストするしか無い	
  
 –  ウィンドウドライバパターンを使って乗り越える
受け入れテストのレイヤ	
        受け入れ基準	
  
                        Cucumber	
  
         Given…	
  
                         FitNesse	
  
         When…	
  
                             …	
  
          Then…	



          実装レイヤ	
  
            	
  
       ドメインの言語を使う	
  
      UIの要素を参照しない	
  


    アプリケーションドライバレイヤ	
  
           	
            ウィンドウドライバを含む	
     特定のアクションを実行して	
  
  結果を返すために、アプリケーションと	
  
 どうやってやり取りすべきか理解している	
  
受け入れ基準レイヤ	
シナリオ: ユーザーの注文を口座から	
  
     	
    	
   	
   	
  正しく引き落とさなければならない	
  
	
  
     	
  前提 ボンドという名前の証券がある	
  
     	
  かつ デイブというユーザーがいて、口座に50ドルある	
  
     	
  もし デイブの名義でログインする	
  
     	
  かつ ボンドという名前の証券を選択する	
  
     	
  かつ 4口買うことにして、それぞれ10ドルである	
  
     	
  かつ その注文が上手くいった	
  
     	
  ならば 口座に10ドル残る	
  
実装レイヤ	
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	
  
	
  
…	
  
	
  
アプリケーションドライバレイヤを上手く定義すると、	
  
  受け入れ基準をテストの実装で表現できる	

                            xUnit	
  などの	
  
                         Unit	
  test	
  framework	
  


       受け入れ基準 兼 実装レイヤ	
  




        アプリケーションドライバレイヤ	
  
               	
            ウィンドウドライバを含む	
         特定のアクションを実行して	
  
      結果を返すために、アプリケーションと	
  
     どうやってやり取りすべきか理解している	
  
実装レイヤ	
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”);	
  
      	
  }	
  
}	
  
	
  
実装レイヤ	
                                                     ユーザー生成・登録や	
  
                                                       証券生成は複雑な処理だが、	
  
                                                              抽象化してシンプルに	
  
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”);	
  
        	
  }	
  
}	
  
	
  
実装レイヤ	
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”);	
  
      	
  }	
  
}	
  
	
  
アンチパターン	
•  実装レイヤでアプリケーションとのやり取りの
   詳細を記述してしまう	
  
 –  (例)アプリケーションのAPIやUIを直接参照する	
  
 –  (結果)APIやUIの変更でテストスイートが崩壊	
  
 –  (解法)やり取りの詳細をアプリケーションドライバ
    レイヤの責務とする
8.3	
  受け入れテストを作成する	
•  この節では、自動受け入れテストをどのよう
   に作るべきかについて議論する
8.3.1	
  アナリストとテスターの役割	
•  チームに一人、ビジネスアナリストがいるべき	
  
•  ビジネスアナリストの役割	
  
 –  顧客やユーザーの代表になる	
  
   •  顧客と協力して、	
  
      –  要件を識別	
  
      –  優先順位付け	
  
   •  開発者と協力して、	
  
      –  開発者がユーザー視点でアプリケーションを理解できるようにす
         る	
  
   •  テスターと協力して、	
  
      –  受け入れ基準が適切か確認	
  
      –  機能が受け入れ基準を満たしているか確認
8.3.1	
  アナリストとテスターの役割	
•  テスターはどんなプロジェクトにも欠かせない	
  
•  テスターの役割	
  
 –  ソフトウェアの品質がどうなっているのか、リリー
    スする準備がどの程度できているのかについて、
    顧客を含むデリバリーチーム全員に理解させる	
  
   •  受け入れ基準の定義	
  with	
  顧客	
  and	
  アナリスト	
  
   •  自動受け入れテスト作成	
  with	
  開発者	
  
   •  探索的テスト	
  
   •  ショーケース
8.3.1	
  アナリストとテスターの役割	
•  誰かに専念させる必要はない	
  
 –  開発者兼アナリスト	
  
 –  アナリスト兼テスター	
  
•  役割を果たす人が常にチームに居ることが重
   要
8.3.2	
  イテレーティブな	
  
    プロジェクトにおける分析	
•  この節では、開発プロセスにイテレーティブな
   ものを使用していることを前提とする
開発者	
       アナリスト	
           テスター	
顧客
イテレーションにおける役割	



受け入れ基準	
                                           テスターによる	
  
                               要件実装	
  
  定義	
                                               テスト	
  
                 短い	
  
                                          デモ	
  
             キックオフミーティング	
  
受け入れ基準定義	
•  アナリスト	
  
  –  定義にほとんどの時間を使う	
  
     •  これによってチームが「Done」を判断でき
        るようになる	
  
  –  テスターや顧客と密接に協力	
  
     •  完了を定義するために測定するべきもの
        を、テスターの経験から伝えてもらえる	
  
     •  要件の本質をテスターに伝えることができ、
        要件のテストに役立ててもらえる
短いキックオフミーティング	
 •  要件が実装される直前に行う	
  
 •  アナリストの役割	
  
  –  要件とその文脈、受け入れ基準を示
     す	
  
 •  テスターと開発者の役割	
  
  –  一緒に作業し、自動受け入れテスト
     一式について合意する	
  
 •  可能であれば顧客も参加	
  
短いキックオフミーティング	
 •  効能	
  
    –  アナリスト	
  
       •  実装やテストのコストが高い要件を作っ
          てしまうことを回避できる	
  
    –  テスター	
  
       •  システムを誤解して、欠陥でないものを
          欠陥として捉えてしまうことを防げる	
  
    –  開発者	
  
       •  関係ないものを実装してしまうことを避
          けられる	
  
要件実装	
•  開発者	
  
  –  アナリストに相談する	
  
     •  要件のよくわからない箇所	
  
     •  要件の問題	
  
     •  要件が解決する問題に対する、効率的
        な他の解決方法の提案	
  
•  デプロイメントパイプラインによって、
   こうしたやり取りが促進される	
  
デモ	
•  開発者が作業を完了した後で行わ
   れる	
  
  –  完了:=	
  ユニットテスト、コンポネントテ
     スト、受け入れテストが通ったという
     こと	
  
•  開発者	
  
  –  アナリスト、テスター、顧客の前でデ
     モをする	
  
デモ	
•  意図したとおりに要件が実現され
   ていることを確認する機会	
  
•  細かい問題が指摘されることも多
   い	
  
 –  CDをやっているならばすぐに対応で
    きるはず・・・	
  
 –  代替案の議論や変更のきっかけとな
    る	
  
•  システムの進化の方向性について、
   チームで理解を共有する機会	
  
テスターによるテスト	
•  デモの後は、テスターによってテス
   トされる	
  
8.3.3	
  実行可能な仕様としての	
  
             受け入れ基準	
•  振る舞い駆動開発の考え方	
  
 –  受け入れ基準はアプリケーションの振る舞いに対
    する顧客の期待という形で書かれるべき	
  
 –  受け入れテストは実行可能な仕様	
  
   •  仕様の陳腐化を防ぐ
8.4	
  アプリケーションドライバレイヤ	
•  テスト対象のシステムとどのようにやり取りす
   るかを理解しているレイヤ	
  
•  APIがドメインの言語で表現される	
  
 –  DSLと考えることが出来る	
  
 –  この場合、ドメインはアプリケーションの仕様	

             受け入れ基準	
  


              実装レイヤ	
  


        アプリケーションドライバレイヤ	
  
8.4.1	
  受け入れ基準の表現方法	
•  外部DSLを使う場合(Cucumber	
  など)	
  
  –  メリット	
  
      •  受け入れ基準がそのまま実行可能な仕様となる	
  
  –  デメリット	
  
      •  実装との同期のオーバーヘッド	
  
•  内部DSLを使う場合(xUnit	
  など)	
  
  –  メリット	
  
      •  複雑なツールを使わない	
  
      •  開発環境の自動補完が使える	
  
  –  デメリット	
  
      •  ドキュメント(受け入れ基準)生成が面倒	
  
          –  xUnit	
  テストケースからフィーチャーやストーリー、ステップをドキュメント
             として生成するのは難しい
8.4.2	
  ウィンドウドライバパターン:	
  
    テストとGUIを疎結合にする	
•  アプリケーションドライバのサブセット	
  
•  GUIとやりとりする	
  
•  抽象レイヤを導入し、受け入れテストとテスト
   対象システムの結合度を減らす	
  
 –  GUIの変更がテストに及ぼす影響を減らしている	
  
•  あらゆるテストはこのレイヤを介してのみUIと
   やりとりする
8.4.2	
  ウィンドウドライバパターン:	
  
    テストとGUIを疎結合にする	
•  GUIの各部分に対して対応するデバイスドラ
   イバを書かなければならない	

  Test	
  Suite	
  A	
   Test	
  Suite	
  B	
   Test	
  Suite	
  C	



       ドライバ1	
               ドライバ1	
                 ドライバ1
レイヤリングなしの場合	
@Test	
  
Public	
  void	
  shouldDeductPaymentFromAccountBalance()	
  {	
  
      	
  //	
  ログイン処理	
  
      	
  selectURL(“hjp://my.test.bank.url”);	
  
      	
  enterText(“userNameFieldID”,	
  “testUserName”);	
  
      	
  enterText(“passwordFieldID”,	
  “testUserName”);	
  
      	
  click(“loginBujonId”);	
  
      	
  waitForResponse(“loginSuccessIndicator”);	
  
	
  
      	
  //	
  支払い処理	
  
      	
  …	
  
	
  
      	
  //	
  	
  asserDons	
  
      	
  …	
  
}	
  
	
  
レイヤリングした場合	
@Test	
  
Public	
  void	
  shouldDeductPaymentFromAccountBalance()	
  {	
  
      	
  AccountPanelDriver	
  accountPanel	
  =	
  new	
  AccountPanelDriver(testContext);	
  
	
  
      	
  //	
  ログイン処理 <-­‐	
  このコメントが不要となる	
  
      	
  accountPanel.login(“testUserName”,	
  “testPassword”);	
  
      	
  accountPanel.assertLoginSucceeded();	
  	
  	
  //	
  ステップごとにアサーションを入れても、	
  
      	
              	
   	
     	
   	
   	
   	
    	
  	
  	
  //	
  テストの意図がぼやけない。	
  
      	
              	
   	
     	
   	
   	
   	
    	
  	
  	
  //	
  Fail-­‐fast	
  が実現された	
  
      	
  	
  
      	
  //	
  支払い処理	
  
      	
  …	
  
	
  
      	
  //	
  	
  asserDons	
  
      	
  …	
  
}	
  
	
  
8.5	
  受け入れテストを実装する	
•  レイヤリングして終わりと思ったら大間違い	
  
•  受け入れテストでは、	
  
 –  特定の状態にセットアップし、	
  
 –  幾つかのアクションを実行し、	
  
 –  結果を検証する	
  
•  テストを不安定にさせない	
  
 –  非同期処理とタイムアウトを制御	
  
 –  データセットを慎重に管理	
  
 –  外部システムとの統合をシミュレート	
  
8.5.1	
  受け入れテストにおける状態	
•  システムとやり取りをするので、状態は必須	
  
 –  振る舞いをテストするには、特定の開始状態にい
    なければならない	
  
•  複雑な状態にテストが依存することを最小限
   に抑える
複雑な状態にテストが依存することを
     最小限に抑える	
•  プロダクションデータのダンプを受け入れテス
   トのデータベースに入れてはならない(キャパ
   シティテストは例外)	
  
•  統制のとれた最小限のデータセットを保守す
   る	
  
 –  正しく動くとわかっている開始地点を確立	
  
  •  データセットをスクリプトとしてバージョン管理	
  
  •  アプリケーションの公開APIを用いてセットアップ(12章)
テストはアトミックであるべき	
•  実行順序に依存しない	
  
 –  追跡が難しいバグを生み出す原因が排除される	
  
 –  並列実行が可能となる
アトミックなテスト	
•  必要な物は全て自分で生成	
  
•  成功・失敗の記録以外に痕跡を残さない	
  
アトミックなテストへのアプローチ	
•  アプリケーションの機能によってスコープを区
   切る	
  
 –  テスト開始時に新しいアカウントを作る	
  
 –  アプリケーションドライバで、新しいアカウントをシ
    ンプルに作成できる基盤を作る
テストケース間で	
  
       状態を共有する場合	
•  そうせざるをえない事もある	
  
•  注意深く設計すること	
  
 –  テストが脆くなりがち	
  
 –  DBにレコード4件書き込み、3番目を取り出す場
    合、テストの前に垂れもレコードを追加しないよう
    にしなければならない	
  
開始状態を保証できない場合	
•  そういうこともある	
  
•  テストを防御的に作ること	
  
 –  テスト開始時に状態が期待通りか確かめる	
  
   •  Fail-­‐fast	
  
 –  相対的な観点からテストする	
  
   •  ×	
  array.push(‘a’)	
  	
  	
  	
  	
  	
  array.size.should	
  be	
  1	
  
         –  テスト開始時に	
  array	
  が空であることを保証できない	
  
   •  ○	
  expect{	
  array.push(‘a’)	
  }.to	
  change	
  {	
  array.size	
  }.by(1)	
  
8.5.2	
  	
  
  プロセス境界・カプセル化・テスト	
•  素直なテストを書かねばならない	
  
 –  特権的なアクセスを要求しない	
  
•  テストしやすくするために設計アプローチを変
   える必要が出てくる	
  
 –  × バックドアを作る	
  
   •  カプセル化が破壊される	
  
     –  リファクタリングを妨げる	
  
     –  テストが壊れやすくなる	
  
 –  ○ コードをより良くモジュール化し、より良くカプ
    セル化する
バックドアが避けられない場合	
•  本当にバックドアしか手がない時のみバックド
   アを使う	
  
 –  外部コンポネントとやり取りするコードを	
  Test	
  
    Double	
  で置き換える	
  
 –  テスト用外部コンポネントを作る	
  
•  バックドアは整備・維持に手がかかるので、
   最後の手段にする
8.5.3	
  非同期とタイムアウトを管理する	
•  非同期システムのテストには、非同期特有の
   問題がある	
  
 –  ユニットテストでは非同期処理を避けるべき	
  
  •  テストが不安定になる	
  
 –  受け入れテストでは非同期処理が避けられない
    ことがある	
  
  •  スレッドやトランザクション
非同期システムのテスト	
  
               特有の問題	
•  問題	
  
   –  テストが失敗したのか、あるいは結果を待ってい
      るだけなのかわからない	
  
•  対策	
  
   –  問題を隔離する	
  :=	
  非同期処理を同期呼び出しの
      背後に隠蔽する
例:ファイル受信箱システム	
•  受信箱(ファイルシステム上の、とあるディレ
   クトリ)をポーリングして、ファイルの収集と
   ファイルが届いたことをメールで通知するシス
   テム
ファイル受信箱システムの	
  
       ユニットテスト	
•  コンポネントを別々にテストする	
  
 –  テストダブルを使ってテスト対象を切り出せる	
  
   •  ファイルシステムをシミュレートする	
  
   •  時計の偽物を作る
ファイル受信箱システムの	
  
       受け入れテスト	
•  ユニットテストよりも更に踏み込んだテストを
   しなければならない	
  
 –  デプロイメントが上手く行ったことをテスト	
  
 –  ポーリングの仕組みが設定できたことをテスト	
  
 –  メールサーバーが正しく設定されたことをテスト	
  
 –  全てが協調して動作することをテスト
ファイル受信箱システムの	
  
       受け入れテスト	
•  ここで問題となるのが以下の2つ	
  
 –  ポーリングの間隔	
  
 –  Eメールが届くまでの時間
理想的なテスト	
public	
  void	
  ShouldSendEmailOnFileReceipt()	
  {	
  
      	
  ClearAllFilesFromInbox();	
  
      	
  DropFileToInbox();	
  
      	
  ConfirmEmailWasReceived();	
  
}	
  
	
                                  シンプルで明確	
  
誤ったテストの実装:	
  
         メールが届く前にアサート	
private	
  void	
  ConfirmEmailWasRecieved()	
  {	
  
      	
  if(!EmailFound())	
  {	
  
      	
   	
  Fail(“メールを受け取れなかった”);	
  
      	
  }	
  
}	
  
                                       テストは失敗するが、	
  
	
                                   問題はプロダクトコードではなく	
  
                                  テストコードにある	
  
正しいテストの実装:	
  
                待つ	
private	
  void	
  ConfirmEmailWasRecieved()	
  {	
  
      	
  Wait(DELAY_PERIOD);	
  
	
  
      	
  if(!EmailFound())	
  {	
  
      	
   	
  Fail(“時間内にメールを受け取れなかった”);	
  
      	
  }	
  
}	
  
	
                                      十分待てば、	
  
                                   妥当なテストとなる	
  
欠点と対策	
•  欠点	
  
   –  待ち時間が容易に積み上がってしまう	
  
•  対策	
  
   –  結果のポーリング	
  
   –  媒介となるイベントを監視
結果のポーリング	
private	
  void	
  ConfirmEmailWasRecieved()	
  {	
  
      	
  TimeStamp 	
  testStart	
  =	
  TimeStamp.NOW;	
  
      	
  do	
  {	
  
      	
   	
  if(EmailFound())	
  {	
  
      	
   	
   	
  return;	
  
      	
   	
  }	
  
      	
   	
  Wait(SMALL_PAUSE);	
  
      	
  }	
  while(TimeStamp.NOW	
  <	
  testStart	
  +	
  DELAY_PERIOD);	
  
      	
  Fail(“時間内にメールを受け取れなかった”);	
  
}	
  
	
  
媒介となるイベントを監視	
•  受信したEメールの処理を行なってくれるサー
   ビスがある場合に使える方法	
  
 –  Eメールが届くと、それに対応してイベントを生成	
  
 –  このイベントを待つことで、テストを高速化する
イベント監視	
private	
  void	
  ConfirmEmailWasRecieved()	
  {	
  
      	
  TimeStamp 	
  testStart	
  =	
  TimeStamp.NOW;	
  
      	
  do	
  {	
  
      	
   	
  if(EmailFound())	
  {	
  
      	
   	
   	
  return;	
  
      	
   	
  }	
  
      	
   	
  Wait(SMALL_PAUSE);	
  
      	
  }	
  while(TimeStamp.NOW	
  <	
  testStart	
  +	
  DELAY_PERIOD);	
  
      	
  Fail(“時間内にメールを受け取れなかった”);	
  
}	
  
	
  
イベント監視	
private	
  boolean	
  emailWasReceived	
  =	
  false;	
  
	
  
private	
  boolean	
  EmailFound()	
  {	
  
      	
  return	
  emailWasReceived;	
  
}	
  
	
  
public	
  void	
  EmailEventHandler(…)	
  {	
  
      	
  emailWasReceived	
  =	
  true;	
  
}	
  



                                    高速化という観点で、意味があるのか?	
  
                                  メールが大量に溜まっている場合には効果あり?	
  
•  ConfirmEmailWasReceived	
  のクライアントに
   とって、このメソッドは同期的であるように見
   える	
  
  –  抽象度の高いテストがシンプルに書ける	
  
  –  この種のコードはアプリケーションドライバレイヤ
     に置いて、再利用すべき	
  
    •  効率的で、信頼できる非同期処理の再利用
8.5.4	
  テストダブルを利用する	
•  自動受け入れテストとユーザー受け入れテス
   トは違う	
  
 –  自動受け入れテストは外部システムと統合された
    環境で実行してはならない	
  
  •  制御可能な環境を提供しなければならない	
  
    –  制御可能	
  :=	
  テスト用初期状態を正しく作れる
受け入れテストの矛盾	
•  我々の目標(受け入れテストの?CDの?)は、
   システムを継続的に統合し、問題を早期に発
   見することである	
  
 –  外部システムと統合するべきということ	
  
•  受け入れテストでは、外部の依存対象による
   影響を最小限に抑えなければならない	
  
 –  外部システムと統合するべきでないということ	
  
外部システムと統合してしまうことの	
  
      問題点	
•  受け入れテストのスコープに外部システムを
   含めてしまうと、システムやその初期状態を
   制御しにくくなる	
  
•  外部システムに重大な負荷がかかる可能性
妥協	
•  外部システムを表現したコンポネントを作成
   する	
  
  –  外部システム1つに対して1コンポネント	
  
  –  外部システムのインターフェイスを表現	
  
•  このコンポネントを、	
  
  –  自システムとのやり取りという観点	
  
  –  外部システムとの通信地点という観点	
  
•  の両方から保証する
自システムとのやり取りの観点	
  
       から保証	
                    設定	
  
 外部システムに対する	
      ファイル	
      外部システムに対する	
  
ローカルインターフェース	
                ローカルインターフェース	


                                 外部システムを	
  
外部システムとのやり取り	
  
                                 シミュレートする	
  
(ゲートウェイ、アダプタ)	
                                  Test	
  Double	




                         外部システムとの通信を表現する	
  
                           Test	
  Double	
  を作成する	
   外部システム
外部システムとの通信地点という観点	
  
      から保証	
    外部システムに対する	
  
   ローカルインターフェース	
                      •  インテグレーションテスト	
  
                        –  統合点の周りに小粒のテスト
                           スイートを作成	
  
   外部システムとのやり取り	
  
                        –  実際に外部システムと統合し
   (ゲートウェイ、アダプタ)	
                           てテストを実行する	




      外部システム
外部システムとの通信を表現する	
  
     Test	
  Double	
  を作成する	
•  メリット	
  
   –  テストの開始地点を構築できる	
  
   –  通信失敗のシミュレーション	
  
   –  エラーが返された時のシミュレーション	
  
   –  高負荷の場合のレスポンスのシミュレーション
インテグレーションテスト:	
  
 外部システムとの統合ポイントをテストする	
•  外部システムとの接点は問題がよく起きる	
  
 –  自システムと外部システムとで共有するデータ構造	
  
 –  通信の頻度	
  
 –  宛先解決の仕組みの設定	
  
 –  外部システムの変更	
  
•  インテグレーションテストでは、こうした問題に
   集中しなければならない
インテグレーションテスト	
•  外部システムが開発中の場合、インター
   フェースの性質が変化するのが普通	
  
 –  スキーマ	
  
 –  システム間の契約	
  
 –  情報の中身	
  
•  どこで合流するかを見極めなければならない
インテグレーションテスト	
•  著者の経験によると、ほとんどのインテグ
   レーションテストでシミュレートすべき明確な
   シナリオがいくつかある	
  
•  そのようなシナリオは少数のテストで網羅す
   ることを勧める	
  
 –  この場合、カバレッジは完璧ではない	
  
 –  しかし、カバレッジを完璧にするのは難しく、費用
    対効果が下がってゆく	
  
インテグレーションテスト	
•  自システムと外部システムとのやり取りを網
   羅するようスコープを定める	
  
 –  外部システムのインターフェイスを完全にテストし
    ようとしてはならない	
  
 –  141ページ「インテグレーションテスト」のガイドラ
    インに従う
インテグレーションテスト	
•  インテグレーションテストの実行頻度	
  
 –  受け入れテストの度に実行	
  
   •  外部システムに負荷がかかってしまう	
  
 –  日に一度、あるいは週に一度	
  
   •  デプロイメントパイプラインの個別のステージとする	
  
   •  キャパシティテストステージの一部とする
8.6	
  受け入れテストステージ	
•  コミットテストを通過したビルド全てに対して実
   行する	
  
•  受け入れテストに失敗したビルドはデプロイし
   てはならない	
  
 –  受け入れテストは曖昧に扱ってはならない	
  
受け入れテストのカバレッジが	
  
     不十分な場合	
•  以下の3つのどれかが起こってしまう	
  
 –  プロセスの最後、開発が完了したと思った頃にバ
    グが見つかり時間をとられる	
  
 –  手作業で受け入れテストやリグレッションテストを
    行い、大量の時間とお金を取られる	
  
 –  品質の悪いソフトウェアをリリースする
自動受け入れテストは	
  
       やった方がいい	
•  極端に期間の短い、人数の少ないプロジェクトで、自動受
   け入れテストの実装からプロジェクトを始めるのはやりす
   ぎ	
  
 –  CIプロセスのステージを1つだけにし、その中でエンドツーエン
    ドテストをした方がいい	
  
•  しかし、規模が大きくなれば、自動受け入れテストの価値
   はコストに見合う	
  
•  巨大なプロジェクトも小さいプロジェクトとしてスタートを切
   る	
  
•  プロジェクトが大きくなると、包括的な自動受け入れテスト
   を作るのは難しい	
  
•  よってどんなプロジェクトでも自動受け入れテストはやった
   方がいい
8.6.1	
  受け入れテストを	
  
         グリーンに保つ	
•  受け入れテストが壊れた場合、チームは手を
   止めて、問題の仕分けを行う必要がある	
  
 –  テストが不安定なのか	
  
 –  環境の設定が問題なのか	
  
 –  アプリケーションが変更され前提が変わったのか	
  
 –  本物の失敗なのか	
  
•  誰かが直ちに対応し、テストが通るようにしな
   ければならない
通らないテストを放置すると	
  
       どうなるか	
•  リリースが近づくにつれ、品質を保証するために、
   受け入れテストをグリーンにしようとする	
  
•  その頃には、受け入れテストの失敗の原因を特
   定するのが難しくなっている	
  
•  時間がないので、テストが削除されたり無視され
   る	
  
•  結果、作業の見積りができず、コードが実際どう
   なっているのかわからないという状況に陥る	
  
犯人と思しき人物を特定せよ	
•  受け入れテスト失敗の原因特定は、ユニット
   テストほど容易ではない	
  
 –  ユニットテストの場合、チェックインした人が犯人	
  
 –  受け入れテストの場合、テストの合間に複数コ
    ミットされる可能性がある	
  
•  どの変更に紐付いて受け入れテストが実行さ
   れたかを追跡できるようにしておくべき
受け入れテストは誰の所有物か?	
•  テストチームの所有物?	
  
 –  開発チームは受け入れテストへの影響を意識せ
    ずに変更を行なってしまう	
  
 –  テストチームが変更に気づくのは開発が終わった
    後であり、その頃には開発者が別のタスクに取り
    掛かっていて、テストチームはテストの修正と新
    たなテストの実装で大変になる
受け入れテストは誰の所有物か?	
•  チーム全体の所有物	
  
 –  開発者が要件の受け入れ基準の実現に集中す
    るようになる	
  
   •  変更の影響を意識するようになる	
  
8.6.2	
  デプロイメントテスト	
•  受け入れテストは、本番環境にテスト環境を
   できるだけ近づけて実行する	
  
 –  資金が許すなら完全に同じであるべき	
  
 –  資金がないなら仮想化を行なって近づけるべき	
  
•  受け入れ基準が満たされていることをテスト
   するとともに、擬似本番環境にデプロイできる
   ことをテストしている	
  
 –  デプロイメントがうまくいく事をテストする最初の
    機会
デプロイメントテスト	
•  デプロイメントテスト	
  
  –  基盤テストや環境テストと呼ばれるスモークテスト	
  
    •  環境が期待通りに設定されることをテスト	
  
    •  システムのコンポネント間の通信チャネルが正しく準
       備され動作することをテスト	
  
  –  デプロイメントが成功したことを確認し、後に続く
     機能的な受け入れテストのための開始地点を構
     築することを目的としている
早めに失敗させる	
•  デプロイメントテストを特別なテストスイートと
   して扱う	
  
 –  デプロイメントテストが失敗したら、受け入れテス
    トステージを直ちに落とす	
  
  •  デプロイメントに失敗したら、当然受け入れテストも失
     敗する	
  
  •  非同期システムのテストでは、失敗するテストで延々と
     待機してしまう
8.7	
  受け入れテストのパフォーマンス	
•  受け入れテストでは、パフォーマンスは二の
   次	
  
 –  実行時間について考える前に、システムや基盤
    がデプロイされ、設定が完了し、起動及び終了が
    出来ていなければならない	
  
•  しかし、高速化するテクニックは数多くある
8.7.1	
  共通のタスクは	
  
      リファクタリングせよ	
•  テストの初期化を共通化する	
  
 –  受け入れテストはステートフル	
  
 –  受け入れテストは状態を共有しない	
  
 –  よってテストの事前条件への初期化のステップを
    共通化する	
  
•  共通化された初期化のステップを効率化する
共通のタスクはリファクタリングせよ	
•  初期化のステップで、UIを叩く代わりに公開
   APIが使えるなら理想的	
  
•  バックドアを使ってテストデータを設定するこ
   とが理にかなっていることもある	
  
 –  テストデータが普通に操作して設定できるデータ
    と異なっている場合もあるので注意しなければな
    らない
8.7.2	
  高価なリソースは共有せよ	
•  「適切な開始状態を作り出す」のを素直にや
   ろうとすると、テストはシンプルで信頼できる
   が、時間がかかってしまう	
  
 –  アプリケーションの起動、初期データの設定、状
    態の初期化…	
  
•  妥協し、高価なリソースを共有する	
  
 –  サーバーベースのアプリケーションなら、システ
    ム自体を共有できる
8.7.3	
  並列テスト	
•  テストを並列に実行する	
  
 –  マルチユーザーのサーバーベースシステムなら
    ばこれが適している	
  
 –  2つのテスト間で相互作用が発生するリスクがな
    いなら、単一のサーバーに対して2つのテストを
    並列実行できる
8.7.4	
  コンピュートグリッドを用いる	
•  利用すべき場合	
  
  –  マルチユーザーでないシステム	
  
  –  高く付くテスト	
  
  –  同時並行でユーザーに使われることをシミュレー
     トするのが重要なテスト	
  
•  いまどきのCIサーバーには、テストサーバー
   のグリッドを管理する機能がついている
8.8	
  まとめ	
•  受け入れテストによって、	
  
  –  チームメンバー全員が、ユーザーの求める価値に集中で
     きる	
  
  –  ソフトウェアが目的にかなっているという自信が増す	
  
  –  システムを大幅に変更してもリグレッションエラーを防ぐ防
     衛策ができる	
  
  –  品質が大幅に改善される	
  
  –  欠陥がいつ発生しても、フィードバックが素早く得られるの
     で、直ちに修正できる	
  
  –  テスターの手が開くので、テスト戦略を考えたり、実行可
     能な仕様を開発したり、探索的テストやユーザーテストを
     実行できる	
  
  –  サイクルタイムを減少させ、継続的な開発を可能にする	
  

More Related Content

Similar to 継続的8章

Lightning Experience 時代のプロセス開発
Lightning Experience 時代のプロセス開発Lightning Experience 時代のプロセス開発
Lightning Experience 時代のプロセス開発Salesforce Developers Japan
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!Shohei Okada
 
111008 silverlight square_datavalidation
111008 silverlight square_datavalidation111008 silverlight square_datavalidation
111008 silverlight square_datavalidationTakayoshi Tanaka
 
Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】
Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】 Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】
Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】 智治 長沢
 
事例からわかる!テスト自動化導入パターン
事例からわかる!テスト自動化導入パターン事例からわかる!テスト自動化導入パターン
事例からわかる!テスト自動化導入パターン友隆 浅黄
 
CodeIgniter入門
CodeIgniter入門CodeIgniter入門
CodeIgniter入門Sho A
 
テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】
テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】
テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】Tomoharu ASAMI
 
AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...
AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...
AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...Amazon Web Services Japan
 
Introduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGoodIntroduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGoodAtsuhiro Kubo
 
Windows PowerShell 2.0 の基礎知識
Windows PowerShell 2.0 の基礎知識Windows PowerShell 2.0 の基礎知識
Windows PowerShell 2.0 の基礎知識shigeya
 
AnsibleおよびDockerで始めるInfrastructure as a Code
AnsibleおよびDockerで始めるInfrastructure as a CodeAnsibleおよびDockerで始めるInfrastructure as a Code
AnsibleおよびDockerで始めるInfrastructure as a CodeSatoru Yoshida
 
Tech talk salesforce mobile sdk
Tech talk   salesforce mobile sdkTech talk   salesforce mobile sdk
Tech talk salesforce mobile sdkKazuki Nakajima
 
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発lalha
 
勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発Kazuki Nakajima
 
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハックjQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハックJun-ichi Sakamoto
 
Continuous delivery chapter4
Continuous delivery chapter4Continuous delivery chapter4
Continuous delivery chapter4favril1
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~normalian
 
jQuery と MVC で実践する標準志向 Web 開発
jQuery と MVC で実践する標準志向 Web 開発jQuery と MVC で実践する標準志向 Web 開発
jQuery と MVC で実践する標準志向 Web 開発Akira Inoue
 

Similar to 継続的8章 (20)

Lightning Experience 時代のプロセス開発
Lightning Experience 時代のプロセス開発Lightning Experience 時代のプロセス開発
Lightning Experience 時代のプロセス開発
 
CruiseControl.NET設置
CruiseControl.NET設置CruiseControl.NET設置
CruiseControl.NET設置
 
ITS fidel
ITS fidelITS fidel
ITS fidel
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
111008 silverlight square_datavalidation
111008 silverlight square_datavalidation111008 silverlight square_datavalidation
111008 silverlight square_datavalidation
 
Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】
Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】 Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】
Team Foundation Server ~ 今を生きるエンジニアのための開発基盤とは 【BPStudy #63】
 
事例からわかる!テスト自動化導入パターン
事例からわかる!テスト自動化導入パターン事例からわかる!テスト自動化導入パターン
事例からわかる!テスト自動化導入パターン
 
CodeIgniter入門
CodeIgniter入門CodeIgniter入門
CodeIgniter入門
 
テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】
テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】
テスト 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第33回】
 
AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...
AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...
AWS Black Belt Tech シリーズ 2015 - AWS CodeCommit & AWS CodePipeline & AWS CodeD...
 
Introduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGoodIntroduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGood
 
Windows PowerShell 2.0 の基礎知識
Windows PowerShell 2.0 の基礎知識Windows PowerShell 2.0 の基礎知識
Windows PowerShell 2.0 の基礎知識
 
AnsibleおよびDockerで始めるInfrastructure as a Code
AnsibleおよびDockerで始めるInfrastructure as a CodeAnsibleおよびDockerで始めるInfrastructure as a Code
AnsibleおよびDockerで始めるInfrastructure as a Code
 
Tech talk salesforce mobile sdk
Tech talk   salesforce mobile sdkTech talk   salesforce mobile sdk
Tech talk salesforce mobile sdk
 
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
 
勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発
 
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハックjQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
 
Continuous delivery chapter4
Continuous delivery chapter4Continuous delivery chapter4
Continuous delivery chapter4
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
 
jQuery と MVC で実践する標準志向 Web 開発
jQuery と MVC で実践する標準志向 Web 開発jQuery と MVC で実践する標準志向 Web 開発
jQuery と MVC で実践する標準志向 Web 開発
 

継続的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の変更でテストスイートが崩壊   –  (解法)やり取りの詳細をアプリケーションドライバ レイヤの責務とする
  • 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をやっているならばすぐに対応で きるはず・・・   –  代替案の議論や変更のきっかけとな る   •  システムの進化の方向性について、 チームで理解を共有する機会  
  • 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  まとめ •  受け入れテストによって、   –  チームメンバー全員が、ユーザーの求める価値に集中で きる   –  ソフトウェアが目的にかなっているという自信が増す   –  システムを大幅に変更してもリグレッションエラーを防ぐ防 衛策ができる   –  品質が大幅に改善される   –  欠陥がいつ発生しても、フィードバックが素早く得られるの で、直ちに修正できる   –  テスターの手が開くので、テスト戦略を考えたり、実行可 能な仕様を開発したり、探索的テストやユーザーテストを 実行できる   –  サイクルタイムを減少させ、継続的な開発を可能にする