SlideShare a Scribd company logo
C# から Java へのプログラム移植で
    体験したTDDの効果は?
 TDD超入門者、 Java 超初心者が体験したパラダイムシフト
            2013.01.19 CLR/H#78

             @furuya02




                         copyright© 2012/01.. by SAPPOROWORKS
自己紹介

      ハンドル      SIN/古谷誠進
      Twitter    @furuya02
      仕事        某社でシステムサポート

札幌ワークスというホームページを中心に、フリーソフトや
技術情報を発信させて頂いております。
本日の内容


1.定義
2.TDDへの階段
3.BlackJumboDogのC#からJavaへの移植
4.私のテスト紹介
5.テストについて説明してみる


                   copyright© 2011/03.. by SAPPOROWORKS
1.定義
 テストとは
開発終了とは




         copyright© 2011/03.. by SAPPOROWORKS
(ユニット)テストとは
    特に1・2象限のテストは、要求仕様や設計のテストを目的とする

                  ビジネス面                                手動

         (2象限)            (3象限)

チ        プロトタイプ           探索                                       製
ー        シュミレーション         ユーザビリティ                                  品
ム                                                                  評
支                                                                  価
援                         (4象限)
          (1象限)
          単体テスト           パフォーマンス
          コンポーネント         負荷
                          セキュリテイ
    自動
                    技術面

実践アジャイルテスト 「アジャイルテストの4象限」より
                            copyright© 2011/03.. by SAPPOROWORKS
ユニットテストで品質保証はできない
        QAは別に実施される必要がある




 QA「ソフトウェアの品質評価テスト」とは違う
 TDDにおけるテストは、仕様把握・分析設計のため
 グリーンの時は、あくまで設計どおり動作しているという
  意味
 顧客が望むとおり動いている保証はない(仕様バグ)
 「保守性が高い」「変更に強い」「リファクタリングしやす
  い」という意味では、品質向上にはなると言える


                   copyright© 2011/03.. by SAPPOROWORKS
(プログラムの)開発終了とは?
                 納期・・・・?




       その使用が終了する時
      「納品時」や「バグ出しが終わった時点」ではない

   動いているコードは触るな <= これでいいのか
   綺麗にリファクタリングされ、いつでも変更可能 <= 理想的
   スパゲティがカオスになって、手が付けられない <= 終焉
   プロトタイプやその場限りで使用するツールは、それなり

                           copyright© 2011/03.. by SAPPOROWORKS
2.TDDへの階段
私の場合・・・・限りなく遠い道のり




           copyright© 2011/03.. by SAPPOROWORKS
TDDへの遠い道のり
   何年もかかるという意味ではないです。人によっては瞬殺かも・・・
                                 完成期
                                 TDD・CI

私・・・今この辺のような気がしてます     第4期(パラダイムシフト)
                       テストのリファクタリング

                第3期(練習)
                どんどん書きたくなる
                テストカオスに陥る
       第2期(入門)
       とりあえず力づくで
       書いてみる
第1期(圏外)
必要性が全く見出せない。でも気になる・・・・
第1期(圏外)
                気にはなっている・・・・・


         キッカケ
          「リファクタリング」 初版2000年6月
         状態
          リファクタリングは、積極的にするようになったが・・・
          テストは書いてない。デグレだらけ
          どうやって書けばいいか全然分からない
          しばらく、ここ状態から抜け出せない

          今、読みな直してみると、既に、分かりやすく説かれていた・・・・

リファクタリング プログラムの体質改善テクニック
マーチン ファウラー著
                           copyright© 2011/03.. by SAPPOROWORKS
第2期(入門)
           ちょっと流行ってるみたいだし・・・・


        キッカケ
         巷で、ちょっと流行って来たから
         読んだらできそうな気がした
        「俺、テスト書いてるぜ」的な
        状態
         試行錯誤
         力ずくでどんどん書く
        ※C#版BlackJumboDogへのテスト追加


レガシーコード改善ガイド テストがないコードはレガシーコードだ!
マイケル・C・フェザーズ 著
                          copyright© 2011/03.. by SAPPOROWORKS
第3期(練習)
       いよいよ、私もテストファーストかぁ



キッカケ
 デグレの早期発見で嬉しくなる
 後から書くことに限界を感じる(面倒、結合性)
状態
 テストファーストへの挑戦が始まる(やっとTDD入門)
 設計に変化が生じる
 大胆なリファクタリングが気前よくできる
※BlackJumboDogのJava移植開始


                     copyright© 2011/03.. by SAPPOROWORKS
第4期(パラダイムシフト)
    初めて知った。テストのある世界ってこんなに素晴らしかったんだ


            キッカケ
             リファクタリングの方法を確立する(自分なりに)
             最新のテスト手法を学ぶ
            状態
             自分なりのルールが芽生える
             今までのテストを書き直す
            テストの量(費用対効果)の感覚が芽生えてくる
            テストなしでは生きられない

JUnit実践入門   体系的に学ぶユニットテストの技法
渡辺 修司 著
                           copyright© 2011/03.. by SAPPOROWORKS
完成期
          すいません、本当のTDDは、良く分かってません(暴露)


                         キッカケ
                          まだ、訪れていない・・・・
                         状態(聞きかじり)
                          TDDのサイクル
                          リズム・スピード
                          Ver管理・テスト・継続的インテグレーション



和田卓人の“テスト駆動開発”講座                    2007/10~12
http://gihyo.jp/dev/serial/01/tdd
                                                 copyright© 2011/03.. by SAPPOROWORKS
3.BlackJumboDogの
     C#からJavaへの移植
昨年夏にJava入門のムック本を買ってから・・・・




               copyright© 2011/03.. by SAPPOROWORKS
進捗状況
TCP/UDP及びテキスト/バイナリの全部を一応終わり、一段落しました


  モジュール         進捗状況

  BJD.EXE(本体)   70%    70%

  FTPサーバ        100%     100%
  DNSサーバ        90%      90%
  SMTPサーバ       0%
  POPサーバ        0%
  TFTPサーバ       0%
  Webサーバ        0%
  Proxyサーバ      0%
  DHCPサーバ       0%
                         copyright© 2011/03.. by SAPPOROWORKS
見た目は似てるが、そう甘く無かった
             私が感じた主な障壁


   Unsigned・goto・Linq・varが無い
   リトルインディアンの問題
   refが無い(1つの戻り値しか許さない) パラメータのクラス化
   例外の扱いが違う(チェック例外/実行時例外)
   unsafeのポインタが使用でいない
   パディング1の構造体が使用できない
   formatの書式が異なる(自動変換は行われない)
   ==による文字列評価は、そくバグ



                     copyright© 2011/03.. by SAPPOROWORKS
.NETのクラスライブラリ風を作成
  とりあえずコンパイルを早く通すために・・・・・
プラグインにコーディング規約を教わる
   とりあえずデフォルトのcheckstyleの言いなりになる




                     copyright© 2011/03.. by SAPPOROWORKS
バグもある程度は教えてくれる
    findbugなかなか・・・・




                copyright© 2011/03.. by SAPPOROWORKS
移植の手順(1)
依存関係の少ない、基本的クラスは既にテストが存在した




    既にテストがある(基本的クラス)




        テストだけを移植




          本体を移植

                copyright© 2011/03.. by SAPPOROWORKS
移植の手順(2)
下位クラスは依存関係がハンパなく、ブラックボックス的テストしか存在しない



             テストがないクラス


          再設計(依存排除・再配置)


               テスト作成


               本体実装

                       copyright© 2011/03.. by SAPPOROWORKS
Java入門のためのユニットテスト
        テストがあれば、間違っていても気にしない




   とりあえずガリガリ書いてみる
   勉強を進めるうちに色々間違いに気づく
   テストを頼りにリファクタリンで修正する
   全面的な構造変換も躊躇なくできる
   テストが無いコードは設計が悪い(主に依存関係)




                     copyright© 2011/03.. by SAPPOROWORKS
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




           copyright© 2011/03.. by SAPPOROWORKS
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




       (1)メソッドは日本語
  やってみるとあまりにも分かりやすいのでハマりました




                     copyright© 2011/03.. by SAPPOROWORKS
メソッドは日本語(1)
結構長い間、抵抗があって躊躇っていたが・・・・




                    Eclipse+JUnit
メソッドは日本語(2)
やってみるとあまりにも分かりやすいのでハマりました




                  ReSharper+NUnit
メソッドは日本語(3)
FTPサーバのテストコード 何のテストが有るか何となく分からないですか・・・




                            Eclipse+JUnit
メソッドは日本語(4)
DNSサーバのテストコード、これ英語で表現できない・・・・




                       Eclipse+JUnit
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




     (2)テストコード定型化
    基本(パラメータ)型 ・ 例外型 ・ 応用型
リファクタリングで整備し、テストコードのカオスから脱出する




                     copyright© 2011/03.. by SAPPOROWORKS
基本型
     変数名を統一することが重要、テスト対象はSystemUnderTest

@Test
public void funcで初期化した数値が返る() throws Exception {
      //setUp
      MyClass sut = new MyClass(123);
      int expected = 123;
      //exercise
      int actual = sut.func();
      //verify
      assertThat(actual, is(expected));
      //TearDown
}                                       Java(Junit)
基本型
  定型コメントで意図を明確にし、パターン外の特異事項のみコメントする

[Test]
public void funcで初期化した数値が返る (){
       //setUp
       var sut = new MyClass(123);
       var expected = 123;
       //exercise
       var actual = sut.Func();
       //verify
       Assert.That(actual, Is.EqualTo(expected));
       //TearDown
}                                                C#(NUnit)
失敗時の表示も定型化される
  いつも同じパターンの方が把握しやすい




                       C#(NUnit)
失敗時の表示も定型化される
  いつも同じパターンの方が把握しやすい




                       Java(JUnit)
テストを読むのがつらくなる
            基本型が無いと、毎回詳しく読まなければならなくなる




                                                              ×
[Test]
public void Test1(){
     var num = 123;
     Assert.That(new MyClass(num).Func(), Is.EqualTo(num));
}

[Test]
public void Test2(){
     var num = 123;
     var myClass = new MyClass(num);
     Assert.Equals(myClass.Func(), num);
                                     copyright© 2011/03.. by SAPPOROWORKS
}
DRY原則は適用しない
                         あくまで基本型にこだわる




                                                             ×
[Test]
public void Test1(){
     var num = 123;
     Confirm(new MyClass(num), num);
}
[Test]
public void Test2() {
     Confirm(new MyClass(567), 567);
}
private void Confirm(MyClass myClass, int num){
     Assert.Equals(num,myClass.Func());
                                    copyright© 2011/03.. by SAPPOROWORKS
}
DRY原則は定型以外に適用する
                        あくまで基本型にこだわる




                                                           〇
[Test]
public void Test1(){
       //setUp
        initialize();
       var sut = new MyClass(CreateParamater(1,true,”TEST”));
       var expected = 123;
       //exercise
       var actual = sut.Func();
       //verify
       Assert.That(actual, Is.EqualTo(expected));
}                                      copyright© 2011/03.. by SAPPOROWORKS
基本型を追及した例
1つのメソッドで1つのテストが原則(1)
              いろいろ試験したい気持ちは分かるが・・・・




                                                            ×
[Test]
public void myClassの動作確認(){
       var sut = new MyClass(123);
       Assert.That(sut.Func(), Is.EqualTo(123));

      sut.Add(1);
      Assert.That(sut.Func(), Is.EqualTo(124));

      sut.Add(2);
       Assert.That(sut.Func(), Is.EqualTo(126));
}
                                       copyright© 2011/03.. by SAPPOROWORKS
1つのメソッドで1つのテストが原則(2)
               基本型重視の姿勢は、後々幸せを運ぶ




                                                    〇
[Test]
public void Addで保持する数字に追加される() {
       //setUp
       var sut = new MyClass(0);
       var expected = 100;
       //exercise
       sut.Add(100);
       var actual = sut.Func();
       //verify
       Assert.That(actual, Is.EqualTo(expected));
}
                      ※このテストはAdd()のテストである
1つのメソッドでテスト対象は1つ
              いろいろ試験したい気持ちは分かるが・・・・




                                                           ×
[Test]
public void myClassの動作確認(){
       var myClass1 = new MyClass(123);
       Assert.That(myClass1 .Func(), Is.EqualTo(123));

      var myClass2 = new MyClass(456);
      Assert.That(myClass2 .Func(), Is.EqualTo(456));

      var myClass3 = new MyClass(789);
      Assert.That(myClass3 .Func(), Is.EqualTo(789));
}
                                      copyright© 2011/03.. by SAPPOROWORKS
基本型(例外の扱い)
チェック例外に対処しないとコンパイルが通らない




                                Java(Junit)
               copyright© 2011/03.. by SAPPOROWORKS
基本型(例外の扱い)
ちゃんとtry-catchすると複雑になる




                                    ×

                                Java(Junit)
               copyright© 2011/03.. by SAPPOROWORKS
基本型(例外の扱い)
       ルール無用でExceptionをthrowしておく




                                   〇

どうせ例外発生はテスト失敗だから・・・
                               Java(Junit)
基本型(例外の扱い)
  .NETの場合、チェック例外は無いので華麗に無視しておく




                           〇
どうせ例外発生はテスト失敗だから・・・
                          C#(NUnit)
例外型
expected属性を使用する(JUnit)




                          〇

                         Java(JUnit)
例外型
ExpectedException属性を使用する(NUnit)




                                  〇

                              C#(NUnit)
基本型(パラメータ)
基本型と同じ、便利で多用される




                  C#(NUnit)
基本型(パラメータ)
基本型と同じ、便利で多用される




                  Java(JUnit)
応用型
状態を保持するクラスは、基本型では冗長になりすぎる場合がある




                  copyright© 2011/03.. by SAPPOROWORKS
応用型
いくつも確認したい事項がある時




           copyright© 2011/03.. by SAPPOROWORKS
応用型
       カオス生成装置になりかねない




※基本型では、あまりに冗長になる場合のみ
※ちょっと油断すると・・・・応用ばかりになってしまう




                 copyright© 2011/03.. by SAPPOROWORKS
定型化
   いつみても見通しの良いテストコードを手に入れたい




 リファクタリングしながら、可能な限り、「基本(パラメータ)」
  及び「例外」の2つの型を追及
 整理して、重複したテストは削除する
 テストコードはクラスのドキュメント(使用方法)となる
 仕様漏れの確認になる
 テストの見直しが嫌にならない



                  copyright© 2011/03.. by SAPPOROWORKS
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




     (3)クライアント・サーバ
初期化・終了処理・共通メソッドによるFTPサーバのテスト




                     copyright© 2011/03.. by SAPPOROWORKS
BeforeClassでサーバを起動
      クラスの初期化
AfterClassでサーバ停止
     クラスの終了処理




            copyright© 2011/03.. by SAPPOROWORKS
Beforeでクライアント起動
    メソッドの初期化処理




            copyright© 2011/03.. by SAPPOROWORKS
Afterでクライアント停止
    メソッドの終了処理




            copyright© 2011/03.. by SAPPOROWORKS
共通メソッドでログイン処理
このメソッドを使用して、ログイン後のテストを行う




               copyright© 2011/03.. by SAPPOROWORKS
クライアントを使用したサーバテスト
     あくまで基本型にこだわる
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




    (4)バイナリデータのテスト
  DNSのパケット解析クラスを実パケットでテストする




                     copyright© 2011/03.. by SAPPOROWORKS
実パケットの採取
パケットの内容(解析結果)は、ここで確認できる




               copyright© 2011/03.. by SAPPOROWORKS
バイナリデータの取得
HexStreamでUDPのデータ部(DNSパケット)をコピーする
文字列でテストクラスに取り込む
    ペーストでStringに格納する
Stringをbyte[]に変換
  共通メソッドでbyte[]に変換する
パケット解析クラスのテスト
パケットモニタと同じ結果が得られるかテストする
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




      (5)ガバレッジの利用
  カバー率は問題ではない、レポートを有効に利用する




                     copyright© 2011/03.. by SAPPOROWORKS
例外テストを作成
Aレコードに::1を飲み込ませると例外が発生する




               copyright© 2011/03.. by SAPPOROWORKS
テストは失敗してしまう
ガバレッジを見てみると、予想外の動作をしているのが分かる




                 copyright© 2011/03.. by SAPPOROWORKS
実装を修正してテストを成功させる
     結果的には仕様論理バグ




             copyright© 2011/03.. by SAPPOROWORKS
TDDのはずなのに・・・
テストが無いのに勢いで実装している?
ガバレッジ100%・・・
         いつまでたっても終わらなくなる



 めざせ100%?
ガバレッジで全部を緑にしようなんて考えると、大変な時間
を費やすことになる・・・・
(ツールの仕様上、100%にはならない)

 ちなみに・・・・
実装側の例外処理を減らしても(品質は低下)、ガバレッジ
は上がる


                    copyright© 2011/03.. by SAPPOROWORKS
4.私のテスト紹介
試行錯誤で得た自分なりのルールや手法




        (6)レッドとブルー
      レッドとブルーの状態を大事にする




                     copyright© 2011/03.. by SAPPOROWORKS
テストが最初に赤くなること
          テストコードも単なるプログラム




これ重要!
TDDでは、1つのサイクルに
入っている



 テストコードも単なるプログラムなので、当然バグる
 テストしているつもりでも、テストになっていない
 最初にちゃんと赤くしてテストの正当性を確かめる
                     copyright© 2011/03.. by SAPPOROWORKS
バグ修正の手順
問題発生時にブルーであれば、「仕様バグ」若しくは、「テスト漏れ」




     問題発生


                         テスト作成



      修正


   ※ちゃんとレッドにしてからバグ修正する
                   copyright© 2011/03.. by SAPPOROWORKS
4.私のテスト紹介
    試行錯誤で得た自分なりのルールや手法




                (7)その他
   プライベートメソッドは、リフレクションでアクセスできる
   Waitは、コンソールに***などを表示
   遅いテストをまとめて別メニューにする
   環境の違いなどでエラーの出たテストは、そのテストを追加する



                         copyright© 2011/03.. by SAPPOROWORKS
5.テストについて説明してみる
   よくある疑問への回答




          copyright© 2011/03.. by SAPPOROWORKS
進捗率(工数)について
        現在の進捗率は?って聞かれたら・・・・




 以前は、一通り動いたらOKとしてきた
 テストを書くようになってからは、テストが必要な場合、そのテスト
  を全部書き終わるOKと言えなくなった
 メンテナンス・仕様変更への対応は非常に楽になった
 何時の間にか、テストを含めた進捗率が正確なものだと感じるよ
  うになった
 技術的負債を計上できるようになった



                       copyright© 2011/03.. by SAPPOROWORKS
テストを書くと仕事が増える?
    作業が少ないのは、技術的負債を多く抱えるという事




   バグフィックス             テスト有のモデル


    仕様変更

   コーディング


早くできるのではなく、技術的負
債をどれだけ残すかという事            テスト無のモデル
                   copyright© 2011/03.. by SAPPOROWORKS
テストを書くと仕事が増える?
 長期・大規模になると技術的負債の割合が大きい




短期間・小規模             長期間・大規模
バグフィックス

 仕様変更               バグフィックス



コーディング                 仕様変更

                     コーディング


               copyright© 2011/03.. by SAPPOROWORKS
テストを書くと仕事が増える?
            費用対効果が重要




 テストを書くと、開発時の工数は間違いなく上がるが、バグ発生
  率は減り、テスト・デバッグを含めたトータルの工数は削減されて
  いるかも知れない
 特に「規模の大きな」又は「長期」なプロジェクトでは、顕著かも知
  れない
 「変更に強い」というあたりが絶対価値だと思われるが、それが必
  要ないというのであれば工数増加だけが問題になるのは否定で
  きない


                   copyright© 2011/03.. by SAPPOROWORKS
テスト駆動は、新たなパラダイム
       今までの認識や価値観などが革命的・劇的に変化する



  Macro
(Lotus123)        C
             (MSC/Turbo C)     C++/C#/Java
                             (オブジェクト指向)

                                                        F#
                                                      (関数型)
                      テストファースト
                      (NUnit/JUnit)

理解度による見えているものが違う
   自分にも見えていないものがまだあるはず・・・
                                copyright© 2011/03.. by SAPPOROWORKS
どうやって書けばいいか分からない
     新しい言語を始めたぐらいの気持ちで取り組むしかない




   初めてプログラムを書いているのと同じ
   小さなプログラムは書けても大きなプログラムは書けない
   一応書けるが、きれいに書けない
   後で読めない



    とにかく練習するしかない
     実は設計手法なのでそう簡単には習得できない

                    copyright© 2011/03.. by SAPPOROWORKS
どうやって書けばいいか分からない
          一応とっかかりを・・・・・例示してみる



多態性の実装
・まず、最初にgetInt() setInt()を普通に実装する
・getShort setShort getLong setLongはTDDで作成する

2.クラスのみミニプログラム
・全体のコードを忘れて、1クラスのみ生成して実行する1
つのプログラムを作成する
・「基本型」をとりあえず書いてみる


                          copyright© 2011/03.. by SAPPOROWORKS
有効性の実感
        2期から3期へのキッカケ



TDDが優れた手法だと気付くタイミング・理由は人そ
れぞれだと思います

 実装しようとしているモジュールの設計が洗練されていく感
  覚を味わったとき
 カオスとなったレガシーコードが少しずつ甦ってきたとき
 回帰テスト前に、思わぬ不具合を早期に検出できたとき
 大胆なリファクタリングを躊躇無くできたとき
 など・・・・
                 copyright© 2011/03.. by SAPPOROWORKS
あなたにとってテストは必要ですか
        1つでも有効性を感じれれば、やってみる価値があると思います




   フィードバックと安心                                    具体的なテストデータ
   リファクタリング                                      習得可能なスキル
   インターフェイスへの意識                                  環境へ非依存
   シンプル設計                                        たくさんコードを書ける
   メンテナンスされたドキュメント                               開発が楽しくなる

    やさしいデスマーチ 「TDDを学ぶべき10の理由」より
    http://d.hatena.ne.jp/shuji_w6e/20111204/1323011355

                                                   copyright© 2011/03.. by SAPPOROWORKS
ターゲットが複数にわたるプロジェクト
          テストによる新たな手法か・・・・




   複数プラットフォーム用のコードは限界がある
   実装漏れ
   仕様変更漏れ
   バグフィックス漏れ



    テストパターンを保守する
     テストが簡潔な仕様書になっている事が前提

                      copyright© 2011/03.. by SAPPOROWORKS
(最後に)品質より価値の追求
      変更への強さが最も大事かもしれない




 バグが100%と取り除いて、仕様通りのプログラムを仕上
  げても、それが顧客の価値に直結するとは限らない
 もともと、仕様決定は一時的な最適解であって、状況の
  変化で変わってくる
 これに追従してこそ、真の価値が生まれる
 テストコードに向き合う際も、カバレッジを上げるとか、
  条件網羅を上げるより、変更への強さを追及するべき
  なのかも知れない


                  copyright© 2011/03.. by SAPPOROWORKS
ご清聴ありがとうございました



    @furuya02




                copyright© 2011/03.. by SAPPOROWORKS

More Related Content

C# から java へのプログラム移植で体験したtddの効果は?