tdd boot camp tokyo for c++ 2014-01 補講
Post on 02-Jul-2015
736 Views
Preview:
DESCRIPTION
TRANSCRIPT
TDD Boot Camp Tokyo for C++ 2014-01 補講
@imagire
• どこまでテストをすれば良いの? • 何をテストすれば良いの?
– テストしやすい物やテストしにくい物は?
TDDで気になること
• テスト手法 • テスト技法
より良いテストをするために
• テスト手法 • テスト技法
より良いテストをするために
• 簡潔・読みやすい・きちんと構成されたテストを作ることができる – テストをきれいに保つには、このパターンで作るのが良い
4フェーズテストパターン
namespace UnitTest1 { TEST_CLASS(TestClassName) { public: TEST_METHOD(TestMethodName) { // Set up – 準備 TestClass sut = new TestClass(); // Exercise – 実行 int actual = sut.calc(0); // Verify – 検証 int expected = 0; Assert::AreEqual (expected, actual); // TearDown – 後処理 delete sut; } }; }
Microsoft.VisualStudio.TestTools.CppUnitTestFramework の構成 namespace UnitTest1
TEST_MODULE_INITIALIZE(methodName)
TEST_MODULE_CLEANUP(methodName)
TEST_CLASS (className1)
TEST_METHOD_INITIALIZE(methodName#)
TEST_METHOD_CLEANUP (methodName#)
TEST_METHOD (methodName1)
}
TEST_CLASS (className2)
TEST_METHOD (methodName2)
… …
• 副作用が無い – オブジェクトの状態が変化しない(書込みしない)
• 同じ状態・パラメータなら同じ結果となる – ランダム性を持たない
テストしやすいシステム
入力
出力
System Under Test
• Ex. リストのpush_backのテスト(データを追加) – 上手く実行されたかどうかは、その後のオブ
ジェクトの状態を調べて判断
副作用があるシステム
// setup std::list<std::string> list; // exercise list.push_back(“hello world!”); // verify int actual_size = list.size(); std::string actual_text = list.back(); Assert::AreEqual (1, actual_size); Assert::AreEqual (“hello world!”, actual_text.c_str());
入力
出力
System Under Test
更新
調査
• 別のシステムが関与している場合が多い – テストの時は都合の良い結果になる関数に差替
同じ結果とならないテスト
入力
出力
System Under Test 呼出
応答 Rand()
テスト時
本番時 Rand()
Rand()
本番用
テスト用
System Under Test 入力
出力
テストダブル
• インターフェイスと実装を分離しテスト時に実装クラスを差し替える
テストダブルの作り方例
入力
出力
System Under Test 呼出
応答
Rand()
Rand()
Rand()
本番用
テスト用
• インターフェイスと実装を分離しテスト時に実装クラスを差し替える – テスト対象のクラス自体にテストのための仕組
みの埋め込み • 煩わしい
– テストコードから差し替えられる仕組みの作成 • 堅牢性の低下
テストダブルの作り方例
入力
出力
System Under Test 呼出
応答
Rand()
Rand()
Rand()
本番用
テスト用
面倒くさい!
• オブジェクトを差し替えてのテスト – 上手くつかえば不要な依存関係がなくなり、テスト
が高速で確実 • ハードウェアの依存性をなくす • 難しい入力を再現 • 時間のかかる外部システムのアクセスを高速化 • 時刻など変化しうる依存性の排除 • 開発中の外部システムの依存を排除 • 設定困難な環境への依存性の排除
– 作成が大変で退屈。バグが起きうる。 • 簡単に作成するための仕組み
– Google C++ Mocking Framework, CppUMock, Boost.Test
テストダブルのライブラリ
• テストダミー – リンクエラーを起こさないための簡単な実装
• テストスタブ – 現在のテストケースの指示通りに値を返す
• テストスパイ – 正しいパラメータが渡されたか記録して検証する
• モックオブジェクト – 呼び出された関数・順序・パラメータが正しいか記録・
検証する。複数の呼び出しに対応 • フェイク オブジェクト
– 省略された実装。直ぐに他の実装を行う為や設定が面倒・時間がかかる部分を置き換える
• フェイク爆弾 – 呼び出されるとテストを失敗させる。通られると困る場
所のテスト
テストダブルのバリエーション
• テスト手法 • テスト技法
より良いテストをするために
• どれだけテストをしないといけないの? – テストしなければバグは見つからない
テストの書き方が分かっても…
32bit = 4,294,967,295通り
少ない手間で早く沢山危険なバグを検出する • テストしなければバグは見つからない
– もれなくテストを行う – もれなくテストを行うためには、思いつきでテストを上げてはいけない
• 単調なテストを物量に任せてこなしても検出率は上がらないし疲労するだけ
• 大事なところをテストする – もっともバグを検出しやすいテスト技法を用いる – バグが起きてはいけない順にテストを行う
基本的なテストの方針
テストのしやすさを考えておけばアプリも良い設計になるはず • 操作性:
– ソフトウェアがうまく動けば動くほどテストはどんどん効率的になる • 観測性:
– 見えるものしかテストできない • 制御性:
– ソフトウェアをうまくコントロールすれば、テストを自動化し最適化できる
• 分解性: – テストの適用範囲を制限することにより、より速やかに問題を切り分
け手際よく再テストを行える • 単純性:
– テストする項目が少なければ少ないほどテストを速やかに行える • 安定性:
– 変更が少なければ少ないほど、テストへの障害が少なくなる • 理解容易性:
– より多くの情報があれば、それだけ手際よくテストが行える
テスト容易性を考慮して アプリケーションの設計を行う
• テストが爆発する原因は組み合わせ – テストする項目が無限にあると主張する人の多くが、
テストの際に何を列挙すれば良いかわかっていない – テストの際には、考慮すべき項目をはじめに明示してから
組み合わせるべき • 組み合わせそのものでなく、理解不足が原因の場合が多々ある
• 質の高いテストの特徴
– 不具合を検出できる可能性が高い – 重複がない – 最善である – 単純すぎず、複雑過ぎない – 検出の方法が明記してあること テストを書き出した時は、これら特徴を備えているか見直してみよう!
テストの設計時に気を付けること
• テストの効率を上げるために、最低限のテストでもれなくテストするには技法も大切 – 同値クラステスト – 境界値テスト – デシジョンテーブル – ペア構成テスト – 制御パステスト – …
テストケース設計
同値クラステスト • パラメータの値が多くの値を取り扱う場合でも、
実際には幾つかのグループに分けられる – ex: イベントの受付け
• ~ 9:45: 受付されない • 9:45 ~10:00: 受付可能 • 10:00 ~11:00: 遅刻対応 • 11:00 ~18:00: 追い返し • 18:00 ~: 出品・閉会
• 各範囲内の5つの時間を調べれば、それぞれの機能が働いているか調べられる
– 1秒おきに検証する必要はない
– 同値クラス内のあるテストケースで欠陥が検出された場合に、同じ同値クラス内のどのテストケースでも同じ欠陥が検出される場合に有効 • 非常に少ない数で状況を抑える事ができる • 境界時間を間違えていた場合には無力
受付されない 受付可能
遅刻対応 追い返し 閉会
境界値テスト • 境界でバグは発生しやすい
– 境界値前後で判定が変わる • 前後の値以外では極端な変化は起きないので、問題は出にくい • 境界値前後で値が変わらなければ逆に境界値の設定がおかしい
と判断しやすい
– 不等号を判断し間違えることがある。だって人間だもの • if (etime<now) • if (!(etime>now))
境界値テスト • 境界値のすぐ上と下をとる
9:45 10:00 11:00 18:00
① ② ③ ④ ⑤
受付時間 研修時間
9:44:59
9:45:00
9:45:01
9:59:59:
10:00:00
10:00:01
10:59:59
11:00:00
11:00:01
17:59:59
18:00:00
18:00:01
受付 前 中 中 中 中 中 中 中 後 後 後 後
研修 前 前 前 前 中 中 中 中 中 中 後 後
デシジョンテーブル: テストケースを減らすには • 条件の集合によって複雑なビジネスルール
を表現する – Ex: 来場時の条件によって、研修に参加できる
か決める
ルール1
ルール2
ルール3
ルール4
ルール5
ルール6
ルール7
ルール8
ルール9
条件 受付 前 前 前 中 中 中 後 後 後 研修 前 中 後 前 中 後 前 中 後 アクション 参加 ○ ? ? ○ △ ? ? × ×
• ?をどうでも良いとみなすと、受付前/後は研修の状況によらず同じアクションをすると見なせる →1つにまとめられる
デシジョンテーブルの圧縮
ルール1 ルール4 ルール5 ルール6 ルール7
条件 受付 前 中 中 中 後 研修 DC(Don’t
Care) 前 中 後 DC(Don’t
Care)
アクション 参加 ○ ○ △ ? ×
ルール1 ルール2 ルール3 ルール4 ルール5 ルール6 ルール7 ルール8 ルール9
条件 受付 前 前 前 中 中 中 後 後 後 研修 前 中 後 前 中 後 前 中 後 アクション 参加 ○ ? ? ○ △ ? ? × ×
・各ルールに関してテストケースを少なくとも1つ作成する ・実装の指針にはなるが、圧縮したものでテストケースが尽くされたと考えるのは危険(実装漏れが起きうるので
ペア構成テスト 不具合について良く知られている事 • 3つ以上の特別な組み合わせによって
はじめて起きる不具合は少ない – ほとんどの欠陥が機能が単に動かないか、
特定のペアの場合に起きるようである – テストの数を効率よく減らすことができる(が、完璧で
はない)
ペア構成テスト • パラメータのバリエーションについて、全てのパラメータ
の場合をテストするのではなく、2つのパラメータに注目した際にすべてのパラメータの組が現れるようにテストケースを作成する – 任意のパラメータの組で、全てのパラメータの場合が現れるように
する – 全ての場合をテストするのと比べて対数のオーダーでしか増えない
Ex: 2つの値を取る3つのパラメータの組み合わせ • 全てのケースを網羅:23=8 • ペア構成テスト:4
– 全ての2つの列について、 全バリエーションが存在する
プリン クッキー チョコ シロップ
ケース1 ○ ○ ○
ケース2 ○
ケース3 ○
ケース4 ○ 4回の注文で、3つのトッピングの 全ての2つの組み合わせは試せる!
ペア構成テストの作成方法 • 直行表
– 変数を識別する – 各変数が取りうる値の数を求める – 列の数が変数の数と同じ以上で、各変数の取りうる値の数に対応する値が、
列に含まれるような直行表を公開されている情報から見つける – 直行表にテスト問題を割りつける – テストケースを作成する
• 全ペアアルゴリズム法 – サイトからプログラムを拾ってくる – 変数が取りうる値をexcelで作成し、テキストで保存する – プログラムを実行する
状態遷移図に関するテストを考えよう • とある状態遷移図
A C
B
D
F
E H I
G J キャンセル
キャンセル
制御パステスト • 命令網羅(Statement coverage(SC)(C0基準)
– コード上のすべての命令を最低一度は実行する
• 判定条件網羅(Decision coverage(DC)) /分岐網羅(Branch Coverage(BC))(C1基準) – コード上のすべての条件判定を一度は実行する
• 条件網羅(condition coverage(CC))
– コード上のすべての条件判定において、1つの条件判定の結果が、真になる場合を最低1回、偽になる場合を最低1回 実行する
– 「A or B」のような判定で、C1なら、「A or B」の結果のtrueかfalseを試すが、CCでは、AがtrueかfalseとBがtrueかfalseの場合を実行する。したがって、「true or false」、「false or tru」と選ぶと、CCの条件は満たすが、C1基準は満たさないような場合も起きうる
• 判定条件/条件網羅(Decision/Condition coverage(DC/CC)) – C1基準を満たすようにCCの組み合わせを選ぶ
• 複数条件網羅(Multiple condition coverage(MCC)) (C2基準) – コード上のすべての条件判定の組み合わせを網羅する
• 経路網羅(Path Coverage(PC)) (C∞基準) – コード上のすべての経路を最低1回は実行する
• コード上のすべての状態を最低一度は訪れる
C0基準
A C
B
D
F
E H I
G J キャンセル
キャンセル
• コード上のすべての分岐を一度は実行する
C1基準
A C
B
D
F
E H I
G J キャンセル
キャンセル
• ループが発生するので、無限にテストケースが生じる
より高い基準
A C
B
D
F
E H J
G I キャンセル
キャンセル
ありがとうございました • 参考資料
– 「ソフトウェアテスト技術」、経営情報学会 第3回 情報システム工学研究部会、西 康晴
– 下記書籍
top related