わんくま同盟 名古屋勉強会 #3 タダで始めるテストファースト入門 C# Express + NUnit biac 機材協力 : 日本インフォメーション㈱ 2008/7/26.

Slides:



Advertisements
Similar presentations
わんくま同盟 名古屋勉強会 #2 Visual Studio 2008 でやる テスト駆動開発 2008/04/26 biac 機材協力 : 日本インフォメーション㈱ Test Driven Development.
Advertisements

わんくま同盟 名古屋勉強会 #17 biac
テストについて 近畿大学大学院 田中大介 資料:
わんくま同盟 福岡勉強会 #4 yield について るーごん. わんくま同盟 福岡勉強会 #4 自己紹介 日本一人口が少ない県に住んでいます。 一昨年まで、ちょっと福岡に住みました。 仕事は主に dbMAGIC 。 プログラミング言語はよく分かりません。 好きなもの ポケモン、ファイブマン、ジェットマン、
Visual Studio 2010 の新機能 Coded UI Test
情報処理実習 第05回 Excelマクロ機能入門 操作マクロ入門.
プログラミング基礎I(再) 山元進.
2008/09/20 TDD 道場 ~ みんな TDD やってみよう! ~.
第11回 整列 ~ シェルソート,クイックソート ~
Visual Studio 2008 でやる テスト駆動開発
Biac /10/25 DI コンテナの本懐 ~ IoC の実装も楽々! biac
第9回 並び替えアルゴリズム ~さまざまなアルゴリズムを比較しよう~.
C言語講座 第4回 ポインタ.
アルゴリズムとデータ構造 2011年6月13日
第6章 2重ループ&配列 2重ループと配列をやります.
2008/09/20 TDD 道場 ~ ぼくと契約して TDD をやってよ! ~.
岩井 儀雄 コンピュータ基礎演習  ー探索、整列ー 岩井 儀雄
第20章 Flyweight ~同じものを共有して無駄をなくす~
タダで始めるテストファースト入門 C# Express + NUnit
も  じ ま ほう 文字の魔法 文字の魔法、っていったいなんでしょう? 文字は、ものすごい魔法を持っているんですよ。
~手続き指向からオブジェクト指向へ[Ⅱ]~
Biac /10/ /10/25 DI コンテナの本懐 ~ IoC の実装も楽々! biac
VBScriptで ユニットテストをやってみる
ペアプロ小劇場 劇団ペケぴー 天野勝 永和システムマネジメント 大熊知栄 アジアパシフィックシステム総研
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
図書館職員のための アプリケーション開発講習会
オブジェクト指向 プログラミング 第十三回 知能情報学部 新田直也.
Microsoft MVP for Development Tools – Visual C++
プログラミング入門 電卓を作ろう・パートIV!!.
プログラミング 4 記憶の割り付け.
Microsoft MVP for Development Tools – Visual C++
TDDとメソッドの外部設計 テストファーストの秘訣 2009/08 biac.
講義では、Cプログラミングの基本を学び 演習では、やや実践的なプログラミングを通して学ぶ
メソッドの外部設計と テストファースト ~ 上手く TDD するために ~
Null ヤバイのでなんとかする takeshik.
Null ヤバイのでなんとかする takeshik.
インタラクティブ・ゲーム制作 プログラミングコース 補足資料
2008/09/20 F# 入門 TDD 道場 ~ みんな TDD やってみよう! ~.
Microsoft MVP for Development Tools – Visual C++
メソッドの外部設計と テストファースト ~ 上手く TDD するために ~
プログラミング 4 整列アルゴリズム.
Visual Studio 2008 でやる テスト駆動開発
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
TDD ってどんな感じ? FizzBuzz を作ってみる 2010/01/22 biac 1.
NGK2013B – 名古屋合同懇親会 2013忘年会 – Kouji
アルゴリズムとデータ構造1 2006年7月11日
アルゴリズムとデータ構造 2011年6月23日
第1章 いよいよプログラミング!! ~文章の表示 printf~
アルゴリズムとプログラミング (Algorithms and Programming)
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
アルゴリズムとデータ構造 2012年7月2日
プログラミング入門 電卓を作ろう・パートI!!.
アルゴリズムとデータ構造 2012年6月11日
アルゴリズムとプログラミング (Algorithms and Programming)
dcNavi:デバッグ支援のための グラフベース推薦システム
アルゴリズムとデータ構造 2011年6月28日
サブゼミ第7回 実装編① オブジェクト型とキャスト.
本当は消去できていない!? ~データを完全消去する方法~
本当は消去できていない!? ~データを完全消去する方法~
nativeの基礎知識 「ポインタ」てなによ!?
アルゴリズムとデータ構造 2013年7月2日
第5章 まだまだ続く反復処理!! ~繰り返しその2 for~
アルゴリズム入門 (Ver /10/07) ・フローチャートとプログラムの基本構造 ・リスト ・合計の計算
JAVA入門⑥ クラスとインスタンス.
How To WPF アプリケーション Part4 By 中博俊.
参考:大きい要素の処理.
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
FPS(続き).
プログラミング入門2 第3回 条件分岐(2) 繰り返し文 篠埜 功.
計算機プログラミングI 第5回 2002年11月7日(木) 配列: 沢山のデータをまとめたデータ どんなものか どうやって使うのか
Presentation transcript:

わんくま同盟 名古屋勉強会 #3 タダで始めるテストファースト入門 C# Express + NUnit biac 機材協力 : 日本インフォメーション㈱ 2008/7/26

わんくま同盟 名古屋勉強会 #3 自己紹介 山本 康彦 ( biac ) – いまだにプログラムを書きたがる 51 歳 – 名古屋のとある ISV 勤務 – 現在、 WPF を使った業務アプリケーションの開 発プロジェクトで品質保証を担当 –MFS Agile を部分的に実施中 もとは機械の設計屋さん – ものごとの見方・考え方が、きっとズレてる

わんくま同盟 名古屋勉強会 #3 用意するもの 開発環境とテストフレームワーク – C# 2008 Express – NUnit あるといいなぁ – 静的コード分析ツール FxCop 1.35 – テストカバレッジ計測ツール PartCover

わんくま同盟 名古屋勉強会 #3 テスト駆動開発 と テストファースト この図の全体がテスト駆動開発 ( TDD ) で、 テストファースト技法はその一部。 ( 点線内 ) テストコード 追加・修正 テスト失敗 ( RED ) 製品コード 追加・修正 テスト成功 ( GREEN ) 製品コード リファクタリング 要求仕様・不具合

わんくま同盟 名古屋勉強会 #3 最初のテスト ソリューションとテストプロジェクトを 作る。 テストプロジェクトに参照設定を追加 nunit.framework テスト : NUnit Framework をちゃんと呼び 出すことができるか ?

わんくま同盟 名古屋勉強会 #3 最初のテスト ( コード ) このテストは失敗します ( レッド ) 失敗させようとして、 失敗した → ちゃんと動いている ! using NUnit.Framework; namespace Wankuma.SorterSampleTest { [TestFixture] public class WankumaSorterTest { [Test] [Description("初めての NUnit テスト")] public void FirstTest() { Assert.Fail("ちゃんと Assert できました! (^^;"); } src00.sln

わんくま同盟 名古屋勉強会 #3

ソートしてくれるクラスを作ろう 仕様 – 入出力は int の配列 – とりあえず、 昇順にソート 最初に考えること – どんなふうに使う ? – クラス名、 メソッドシグネチャを決める int[] input = ・・・ WankumaSorter sorter = new WankumaSorter(); int[] result = sorter.Sort(input);

わんくま同盟 名古屋勉強会 #3 テストケース : n = 1 最初は、 仕様の一番簡単なところから。 n = 1 のとき 入力 : int[] input = { 7 } // 数字 1 つ 結果 : int[] result = { 7 } ※ 簡単なところから、 テストをちょこっと、 製 品をちょこっと … 考えなきゃいけないことのスコープを小さくし て、 シンプルに進めていく。

わんくま同盟 名古屋勉強会 #3 テストケース : n = 1 ( テストコード ) ※ 検証用比較データ ( 上では 1 とか 7 ) は、 テスト対象とは独立して生成したものであること。 [Test] [Description("n=1 のとき (何もしない)")] public void SortTestWith1Item() { // テストの準備 int[] input = { 7 }; // テスト実行 WankumaSorter sorter = new WankumaSorter(); int[] result = sorter.Sort(input); // テスト結果の検証 Assert.AreEqual(1, result.Length); Assert.AreEqual(7, result[0]); // 使ったリソースの後始末 … 今回は無し }

わんくま同盟 名古屋勉強会 #3 テストケース : n = 1 ( 製品コード ) テストを通るギリギリのコードで製品を実装 していく。 1. まず、 コンパイルが通るように。 製品のプロ ジェクトと WankumaSorter クラスを作る。 namespace Wankuma.SorterSample { public class WankumaSorter { public int[] Sort(int[] input) { return null; // ← とりあえず何か返す }

わんくま同盟 名古屋勉強会 #3 2. テスト実行 --- 失敗します ( RED ) – まだ実装のまともな中身が無いんですから、 失敗しなきゃいけないですね。 ちゃんと失敗 することを確認します。 – 失敗するはずだと思っていて、 万一成功して しまったら … なにか見落としていることがあ るはずですね。

わんくま同盟 名古屋勉強会 #3 3. 製品の実装 --- テストに通る最小限度 – このテストを通すには、 { 7 } を返してやれば いいんです。 ( シンプルに ! ) 4. テスト実行 --- 成功します ( GREEN ! ) namespace Wankuma.SorterSample { public class WankumaSorter { public int[] Sort(int[] input) { return new int[]{7}; } src01.sln

わんくま同盟 名古屋勉強会 #3 宿題 – その 1 最初に決めておくべきことは、これで OK? ※ 帰ってくるのは同じオブジェクト ? それとも ? → Assert.AreSame() または Assert.AreNotSame() を使ってテスト

わんくま同盟 名古屋勉強会 #3 テストケース : n = 2 n = 2 のとき 入力 : int[] input = { 3, 5 } // 数字 2 つ 結果 : int[] result = { 3, 5 } … これは、 何もせずそのまま返せば OK になっ ちゃうと思いますよね ? 簡単すぎなので、 パス。 入力 : int[] input = { 5, 3 } // 数字 2 つ 結果 : int[] result = { 3, 5 } … これなら、 ちょっと製品の実装が進みそう。

わんくま同盟 名古屋勉強会 #3 テストケース : n = 2 ( テストコード ) ※ ちゃんとテストは失敗しますね? これから実装することに意味がある、 というものです [Test] [Description("n=2 のとき。 逆順なら入れ替え。")] public void SortTestWith2Items() { int[] input = { 5, 3 }; WankumaSorter sorter = new WankumaSorter(); int[] result = sorter.Sort(input); CollectionAssert.AreEqual( new int[] { 3, 5 }, result ); }

わんくま同盟 名古屋勉強会 #3 テストケース : n = 2 ( 製品コード ) こんな実装でどうでしょう ? さっき作ったテスト SortTestWith2Items() を 流すと … グリーン ! これで OK? public int[] Sort(int[] input) { //return new int[]{7}; if (input[0] > input[1]) { int work = input[0]; input[0] = input[1]; input[1] = work; } return input; }

わんくま同盟 名古屋勉強会 #3 テストを全部流してみましょう … レッド !? orz なぜですか ? n = 1 のときも、 2 つあると思って比較しちゃうからで すね。 Sort() の最初に、 こんなのを付け加えて if (input.Length == 1) return input; テストは …? はい、オールグリーン ! ※ いいかげんな実装だと思うでしょう。 しかし、 入力される配列要素数が 1 または 2 である、 という前提が正しいなら、 これで製品と して OK なんですよ。 public メソッドですから、 ガード句 if (input.Length > 2) throw ArgumentOutOfRangeException(); なんてのをメソッドの先頭に加えれば完璧。

わんくま同盟 名古屋勉強会 #3 ちょっとリファクタリング 製品コードの int work = input[0]; input[0] = input[1]; input[1] = work; の部分は、 きっとこれからも使うでしょう。 この 3 行で、 値を入れ替えるという操作をやっています。 リファクタリングして、 値を入れ替えるというメソッドにしておき ましょう。 ※ Express でも、メソッドの抽出リファクタリングをサポートする機能は付いています。 if (input[0] > input[1]) { Swap(ref input[0], ref input[1]); } private static void Swap(ref int n, ref int m) { int work = n; n = m; m = work; }

わんくま同盟 名古屋勉強会 #3 リファクタリングしたら、 また全部のテストを 流して、 なにも壊していないことを確認してお きましょう。 ※ テストもリファクタリングしましょうか。 テストの実行と結果の検証を区別するため、 int[] result = sorter.Sort(input); CollectionAssert.AreEqual(new int[] { 3, 5 }, result); などと書いてきましたけど。 まぎらわしくなければ、 CollectionAssert.AreEqual(new int[] { 3, 5 }, sorter.Sort(input)); と 1 行にまとめて書いちゃっても同じですよね。 src02.sln

わんくま同盟 名古屋勉強会 #3 テストケース : n = 3 n = 3 のとき 入力 : int[] input = { 3, 7, 5 } // 数字 3 つ 結果 : int[] result = { 3, 5, 7 } … これは失敗するでしょう。 ※ どんなテストをどんな順序で作っていくと、効率よく製 品コードが育っていくか … これは、 テストファーストで作っていくときの醍醐味 であり、 最も難しいところでもあります。

わんくま同盟 名古屋勉強会 #3 テストケース : n = 3 ( テストコード ) ※レッドを確認したら、 製品コードを変えます。 こんどは、配列の 2 つめと 3 つめも比較して、 逆順だったら入れ替 えるロジックを追加しましょうか ? いや、 もう先が見えてますよね ? 4 つになったら、 また同じことが … [Test] [Description("n=3 のとき。")] public void SortTestWith3Items() { int[] input = { 3, 7, 5 }; WankumaSorter sorter = new WankumaSorter(); CollectionAssert.AreEqual( new int[] { 3, 5, 7 }, sorter.Sort(input) ); }

わんくま同盟 名古屋勉強会 #3 テストケース : n = 3 ( 製品コード ) そこで、 for 文で書き直すことにします。 public int[] Sort(int[] input) { if (input.Length == 1) return input; for (int i = 0; i < (input.Length - 1); i++) { if (input[i] > input[i+1]) { Swap(ref input[i], ref input[i+1]); } return input; }

わんくま同盟 名古屋勉強会 #3 テストケース : n = 3 ( テストコード ) ・・・はい、 オールグリーン ! これで OK? ちょっとテストがヌルイような気がしませんか ? n = 3 のとき 入力 : int[] input = { 7, 5, 3 } // 数字 3 つ 結果 : int[] result = { 3, 5, 7 } これはどうでしょう ? テストを追加して、 走らせてみると … レッド !?

わんくま同盟 名古屋勉強会 #3 Wankuma.SorterSampleTest.WankumaSorterTest.SortTestWith3Items: Expected and actual are both Values differ at index [0] Expected: 3 But was: 5 配列の先頭が 3 になっていて欲しいのに、 帰ってきたのは 5 です 。 なぜでしょう ? 隣同士の交換を、 先頭から見て行って一回ずつしかやってないから ですね。 7, 5, 3 ↓ 0 番と 1 番を比較・交換 5, 7, 3 ↓ 1 番と 2 番を比較・交換 5, 3, 7 ← いまココ

わんくま同盟 名古屋勉強会 #3 テストケース : n = 3 ( 製品コード ) for ループ 1 回で、一番大きな数字が一番 後ろに来ました。 そこは確定でしょう。 けれど、 そこより前はまだ大小関係が入 り乱れています。 外側に for ループを追加して、 内側の for ループの終了位置を一つずつ減らしなが ら、ループを繰り返してあげる必要があ るみたいです。

わんくま同盟 名古屋勉強会 #3 さぁ、これで … オールグリーン ! いくつか確認のためのテストケースを追加して みましょう。 ( 宿題その 2 ) それらは、 最初からグリーンになるはずのテス トです。 src03.sln for (int j = input.Length - 1; j > 0; j--) { for (int i = 0; i < j; i++) { if (input[i] > input[i + 1]) { Swap(ref input[i], ref input[i + 1]); }

わんくま同盟 名古屋勉強会 #3

ムダな子はいねぇが~ !? 結局、 ソートのロジックは二重ループになりま した。 ちょっといじわるなテストを考えてみます。 n = 5 のとき 入力配列 : 1, 2, 3, 5, 7 ( 数字 5 つ ) 結果配列 : 1, 2, 3, 5, 7 このとき、 Sort() の中で、 大小比較が何回行わ れるでしょう ? 頭から比較していって最後まで 4 回比較してみ れば、 すでに整列していることが分かります。 4 回より多く比較するのはムダってものです。

わんくま同盟 名古屋勉強会 #3 またちょびッとリファクタリング そこで、 比較回数を計測できるようにリ ファクタリングしてから、プローブを突 っ込みます。 リファクタリング - 比較部分をメソッドに 切り出す if (IsNotInOrder(input[i], input[i + 1])) { Swap(ref input[i], ref input[i + 1]); } private static bool IsNotInOrder(int lead, int trail ) { return (lead > trail); }

わんくま同盟 名古屋勉強会 #3 テストプローブの挿入 ( 製品コード ) オールグリーンを確認したら、 プローブ を仕込みます。 #if DEBUG public static int TestCompareCount; #endif private static bool IsNotInOrder(int lead, int trail ) { #if DEBUG TestCompareCount++; #endif return (lead > trail); }

わんくま同盟 名古屋勉強会 #3 テストケース : 最小の比較回数 ( テストコード ) すると、 比較は 4 回だけにしてほしい、 というテストが書けます。 [Test] [Description("n=5 のとき。 最初から整列していると、比較は 4回。")] public void SortTestWith5Items() { #if DEBUG // ←プローブは DEBUG 時のみ有効なので、 テストも。 int[] input = { 1, 2, 3, 5, 7 }; WankumaSorter sorter = new WankumaSorter(); sorter.TestCompareCount = 0; CollectionAssert.AreEqual(new int[] { 1, 2, 3, 5, 7 }, sorter.Sort(input)); // ←念のためソートできてることを確認 Assert.AreEqual(4, sorter.TestCompareCount); #endif }

わんくま同盟 名古屋勉強会 #3 テストしてみましょう … レッドです。 Wankuma.SorterSampleTest.WankumaSorterTest.SortTestWith5Items: Expected: 4 But was: 10 なんと 10 回も比較しています。 これはどうしたものでしょう …? ひとつの手として、 Swap() した回数を数えて おいて、 内側のループを抜けたときに 1 回も交 換していなかったら、もう比較する必要も無い 、と判定してやるのはどうでしょう ?

わんくま同盟 名古屋勉強会 #3 Swap カウンタの導入 ( 製品コード ) Swap() メソッドを改修します。 こんどのカウンタは、 さっきのプローブ用のとは違っ て、 どんな呼ばれ方をするか分からない製品コードの 部分になりますから、 static ではダメです。 ちゃんとメ ンバ変数にしておきましょう。 private int _swapCount; private void Swap(ref int n, ref int m) { this._swapCount++; int work = n; n = m; m = work; }

わんくま同盟 名古屋勉強会 #3 そして、 内側のループに入る前に _swapCount をゼロ クリアして、出てきたときにゼロのままだったら、 ソ ート終了と判定します。 public int[] Sort(int[] input) { if (input.Length == 1) return input; for (int stop = input.Length - 1; stop > 0; stop--) { this._swapCount = 0; for (int i = 0; i < stop; i++) { if (IsNotInOrder(input[i], input[i + 1])) { Swap(ref input[i], ref input[i + 1]); } if ( this._swapCount == 0 ) break; } return input; } // src04.sln

わんくま同盟 名古屋勉強会 #3 宿題 ( その 3) まだ不足しているテストケースがある。 降順にもソートせよ。 昇順 / 降順の切り替えをどうやるかも決定 せよ。 ( ただし、 既存のテストコードは、 そのまま通ること。 ) int 以外の型も使えるように拡張せよ。 ( 数 値だけでなく、 文字列はどうか ?) ソートのロジックを違うものに切り替え られるようにせよ。 ( デザインパターンの 練習 )

わんくま同盟 名古屋勉強会 #3 補足 : 例外が出るところをテスト 製品コードから例外が出る ( そういう仕様 である ) ことを確認するためのテスト ExpectedException 属性を使うか、 ある いは、 次のように try ~ catch する。 WankumaSorter sorter = new WankumaSorter(); try { int[] result = sorter.Sort(null); Assert.Fail( “ この行に来たらアウト!"); } catch (ArgumentNullException) { // OK! --- ここで例外メッセージの検査なども出来る }

わんくま同盟 名古屋勉強会 #3 参考 URL –NUnit 入門 Test First のススメ ( 川俣 晶 ) – 「テスト駆動開発」はプログラマのストレスを軽減するか ? ( 川 俣 晶 ) –.NET 開発者のためのリファクタリング入門 ( 川俣 晶 ) 書籍 – テスト駆動開発入門 ( ケント ベック ) テスト駆動開発入門 ( ケント ベック ) –Microsoft.NET でのテスト駆動開発 ( ジェームス・ニューカーク )Microsoft.NET でのテスト駆動開発 ( ジェームス・ニューカーク ) – リファクタリング ― プログラムの体質改善テクニック ( マーチ ン ファウラー ) リファクタリング ― プログラムの体質改善テクニック ( マーチ ン ファウラー )