Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

xUnitハンズオン第3回テキスト

355 views

Published on

職場で開催したハンズオンの資料。

Published in: Software
  • Be the first to comment

  • Be the first to like this

xUnitハンズオン第3回テキスト

  1. 1. xUnitハンズオン xUnitフレームワークを通じた プログラミング&テスト・スキルUP
  2. 2. はじめに 再掲
  3. 3. 開催概要 • 開催日時 • 2016/12/27 火曜17時 • 2016/1/5~1/19 木曜17時(1/26は予備日) • 会場 • CS+Lync • 持ち物 • Visual Studio 2013もしくは2015 再掲
  4. 4. テキストとサンプルコード • 社内の共有フォルダ • 後ほどメールで連絡させてもらいます。 • SlideShare&GitHub • オンラインからも取得できるようにしておきます。 • SlideShare :http://www.slideshare.net/mizukyfujitani • GitHub :https://github.com/mizukyf 再掲
  5. 5. 目的 • プログラミング・スキルUP • C#/.NETの言語仕様を実践的に理解する • LambdaやLINQといった「積極活用が望まれながら嫌煙されがち」な 事項のノウハウを得る • OOPにおけるモジュール化の「あるべき」を理解する • テスト・スキルUP • 「テストしにくいコード」をテストする工夫をできるようになる • 「テストしやすいコード」(≒品質高いコード)を意識したコーディ ングやレビューができるようになる 再掲
  6. 6. そもそも前提として・・・ そこから一歩進んで • そもそも前提として • 「画面を突っつく」≠UT という事実を理解する • 自分のプロジェクトでUTを実施する基礎知識を得る • そこから一歩進んで • ゆくゆくは"Hot Spot"(改修のたびに障害を起こす類のモジュール) の単体テスト製造および継続メンテナンスの体制を構築していきたい 「志が低い」と言われそうですが、A___システムやB___システム ではこれが限界なのではないかと考えています。。。 再掲
  7. 7. ようするに • ハンズオンの目的は「UTを極める」ことにはない。 • UTを手段として自分たちのスキルUPするきっかけ提供。 • 自分のためのPlaygroundを手に入れたつもりで遊んでほしい。 • xUnitについてもっと知りたいという人は・・・ ? ? Javaneseな方は JSerな方は C#な方は TypeScriptな方は 再掲
  8. 8. 各回のコンテンツ(予定) 日付 会場 コンテンツ 2016/12/27 コラボレーション スペースN/E ○ハンズオンの開催概要 ○環境構築とはじめてのUTプロジェクト 2017/1/5 セミナールームX ○テストクラスの書き方 ○アサーションの種類 2017/1/12 コラボレーション スペースN/E ○テストできる条件 ○テストしやすい条件 2017/1/19 セミナールームY ○TDDの紹介 ○CIツールによる自動テスト体制構築 2017/1/26 コラボレーション スペースW/S 予備回 再掲
  9. 9. 前回の振り返り
  10. 10. まとめ • UTを作成するための部品について初歩的知識を得た。 • 戻り値が特定の値であること、特定の範囲内であること、特定 の値を含むこと、例外をスローすること、などなどの条件(制 約)を使ってメソッドの仕様を表現できるようになった。
  11. 11. サンプル・ソリューションのオープン 1. サンプル・ソリューションZIPをダウンロード 2. ZIPファイルを展開 3. Visual Studioでオープン 4. NuGetパッケージの復元(VS2013の手順は次項参照) 5. アプリケーションの仕様を確認(講師から説明) 6. メイン・プロジェクト指定クラスに対応するTestFixtureク ラスを作成する 7. とりあえずテストを実行してみる ※すでにテスト・プロジェクトとプロジェクト間参照、Nunitな どの必要なアセンブリの参照追加は終わっている。 作業
  12. 12. VS2013 NuGetパッケージの復元 • ソリューション エクスプローラ上でソリューションを右ク リック→[NuGet パッケージの復元の有効化]をクリック • 確認ダイアログが表示されるので[はい]をクリック • 再度ソリューションを右クリック→[ソリューションのNuGet パッケージの管理]をクリック • [復元]をクリック 参考
  13. 13. テスタビリティ
  14. 14. テスタビリティ • 第1回・第2回でテスト対象としたコードは「テスト可能」なも のだった。 • つまり、テスト可能なつくりになっていたし、実際テスト可能 になるようにつくっていた。 • 実際にA___システムやB___システムを構成しているクラスを 見ると、いろいろと「厄介なこと」がわかってくる。
  15. 15. そもそもUTとは? • UTとは? • API(公開されたクラスやそのメソッド)がそれ単体でその仕様通り に振る舞うことを検証〔test〕すること。 • ≒APIそれ単体の仕様を機械言語で表明〔assertion〕すること。 • どのように? • (自家撞着的だが)APIそれ単体を検証できるような状況を用意する ことによって。 • つまり、UTはアプリケーションの「あるがまま」を検証するという受 動的なものではない。アプリケーションをその構成要素に分解してそ れらの振る舞いを検証するため「実験の合理的組織化」を行うという 能動的なもの※1。 ※1 G・バシュラール『科学認識論』より。「無限小の物理学のこうした深層領域にすすむと実在が物理学的に は個体性を失うとすれば、科学者は、自分の実験の精度を大きくするにつれて、その実験の合理的組織化にいっ そう大きな重要性を与えるようになる」。
  16. 16. それができない場合は? • UTは不可能。 • 「どうしたらUTできる?」と悩む余地などない。 • 「解決できない問題は立て方がわるい問題である」※1 • =そんなAPIを作ってはいけない。 ※1 G・バシュラール前掲書より。「解決できない問題は立て方がわるい問題であり、実現できないものとして 記述される実験は与件のなかに不可能なことが含まれている実験であると論断してもかまわないだろう」
  17. 17. ではUT可能となる条件とは? • テストできる条件 1. 公開されていること 2. 仕様がわかっていること(実装は不要) 3. 初期化ができること(cf. ASP.NET WebForm) 4. 「副作用」を制御できること(後述) 5. 条件が一定なら何度実行しても結果が変わらないこと • テストしやすい条件 1. 「副作用」がないこと(後述) 2. 初期化が簡単であること 3. 実行に時間がかからないこと 4. 依存するモジュールのモックを指定できること 実は4つ目と同じこ とを言っている
  18. 18. テストできる条件 (必要条件)
  19. 19. テストできる条件: 1. 公開されていること • テスト・プロジェクト側のコードからアクセスできないコード はテストできない。 • Javaでいえばアクセシビリティがprivateとなっているクラスやメソッ ドはテストできない。 • C#でいえばアクセシビリティがinternal以下となっているクラスやメ ソッドはテストできない。
  20. 20. テストできる条件: 2. 仕様がわかっていること • 検証すべき仕様がわかっていなければ、仕様の検証はできない。 • これ以上の説明は不要なはず。
  21. 21. テストできる条件: 3. 初期化ができること • テスト・プロジェクト側のコードで初期化できない場合も当然 APIのテストはできない。 • 例: • コンストラクタが秘匿されており、ファクトリも提供されていない。 • コンストラクタは公開されているが、そのパラメータをテスト・プロ ジェクト側で用意することができない。
  22. 22. サンプル・コードの確認 • アクセシビリティ • 仕様の記載 • 初期化の可能性 • ~Service1と2のちがい(~Service2でも実装クラスのドキュ メントはまだ不足している) 作業
  23. 23. GetCurrentDateTime()以外のテスト • 実装されているメソッド: • 仕様どおり実装されているかAssert.That()で検証する • 実装されていないメソッド: • 同じようにAssert.That()でテストするコードを記述する • 絶対に失敗するテストになる 作業
  24. 24. テストできる条件: 4. 「副作用」を制御できること • 副作用(side effect)を持つAPI(クラスやメソッド)のテス トは難しい。 • 副作用を制御(統制)してテスト可能にする必要がある。
  25. 25. 副作用とは何か: メリキャット※1の場合 A) 「髪を梳かして来い」と言われたので、しぶしぶ身繕いに行 くついでに、火の付いた従兄のパイプを屑籠に放り込んでお いた B) 父親に「悪い子は夕食抜きだ」と言われ、すごすご自室に戻 るまえにシュガーポットに殺鼠剤を入れておいた(叔父叔母 や弟や母親はともかく、大好きなコンスタンス※2は砂糖を使 わないから大丈夫) ※1 メアリ・キャサリン・ブラックウッド。S・ジャクスン『ずっとお城で暮らしてる』の主人公。19世紀中頃、 アメリカ合衆国の上流階層の娘。両親が残した大邸宅で姉・叔父と引きこもり生活をエンジョイ中。 ※2 メリキャットの姉。メリキャットはコンスタンスが大好き、コンスタンスはメリキャットが大好き。
  26. 26. 副作用とは何か: 情報工学の世界の場合 • 副作用なし • 例: • 1+1は絶対に2 • "hello".Times(2)※1の結果は絶対に"hellohello"である • 副作用あり • 例: • new StreamReader("hello.txt").ReadToEnd()の結果はファイル内容次第 • new Random().Next(10)の結果はランダム※2 • Console.WriteLine("ca va?")は結果を返さない • DateTime.Nowは「現在の日時」を返す(「現在」っていつ?) • elisabeth.Greet()の戻り値は予めelisabeth.Personality = xxで設定された値次第 ※3 • すべて「むき出しの副作用」の例だが、こうしたAPIを利用している APIもまた当然「副作用」を持つことになる ※1 第1回のサンプル・コードとして登場した拡張メソッド。 ※2 各言語が標準で備える乱数生成器が実際にどの程度厳密にランダムな値を生成するかはその実装のアルゴ リズム次第。例えばHaskellのそれは実際にはまったくランダムではない。しかし副作用を持つ点は変わらない。 ※3 再びS・ジャクスンの『鳥の巣』の主人公。リジー、ベス、ベッツィ、ベティの4重人格障害。
  27. 27. 副作用とは何か: 情報工学の世界の場合 • 「副作用」(side-effect)とは? • プログラムの内部もしくはプログラムの外部(JVMやCLRの)外部の「状 態」に働きかけること。 • 副作用を持つAPI(クラスやメソッド)のテストは難しい。 • 違和感がある? 「そうはいっても例えばConsle.WriteLine()の目的は外部の状態(コンソー ル表示)に働きかけること。なのに副作用」? ⇒関数の戻り値はその引数のみによって説明がつくべきだとする、数学的も しくは関数型プログラミング(FP)の見地で定義された言葉だから。 • 「副作用」を持つ処理とは? • 戻り値がその引数のみによっては説明がつかない処理。 • ≠戻り値がその引数のみによって説明できる処理 • =参照等価(referential transparency)な関数 • =純粋関数
  28. 28. つまるところ・・・ • 副作用は意外とありふれている。 • JVMやCLRの外にアクセスする処理はなんであれ─ファイルI/O、コン ソールI/O、ネットワークI/O、日時取得、乱数取得、エトセトラ─す べて副作用 • プログラムの内部の「状態」にアクセスする処理もなんであれ ─setter/getterを通じたものであれ、何かの「ついでに」フィールド に設定されるものであれ─すべて副作用 • にもかかわらず・・・ • 副作用を持つロジックの検証はすごく面倒。 • どころか、「まったく不可能」ということもある。 • だいたい、「面倒」というだけで、時間の限られた業務のなかでは 「不可能」にちかくなるだろう。
  29. 29. というわけで・・・ • アプリケーションのなかで副作用を持つ箇所は、可能な限り、 全力を以て、徹底的に、局所化し、制御下(統制下)におかな くてはならない。 • 例外はない。
  30. 30. 制御(統制)─ 脱・副作用/対・副作用の方法 A) 引数と戻り値で表現する 1. 引数で渡せるものならそうする 2. 戻り値で返せるものならそうする B) 「関心の分離」(separation of concerns)を遂行する 1. メソッドに実現させようとしている「事項」(concern)を腑分けし て、それぞれに応じたメソッドに分解する※1 2. 「事項」がアプリケーションの主機能(主関心)とそうでない機能 (関心)とに分けられるなら、後者をAOPに移行する※2 C) 副作用部分にモック(後述)を導入する I/Oなどを担当する部分を別オブジェクト化。しかもクラスではなくイ ンターフェースを介して参照させる。そして、インターフェースの実装 を差し替える手段を用意する。 D) タリオの法にうったえる 「目には目を歯には歯を、副作用には副作用を」というわけで、環境変 数やロケール(CLRではカルチャー)に介入してしまう。 ※1 つまり「AのついでにBもする」というメソッドを分解して、「Aをする」メソッドと「Bをする」メソッド という2つに分ける。 ※2 AOPについてはB・A・テイト、J・ゲットランド共著『軽快なJava―Better,Faster,Lighter Java』などを参 照のこと。
  31. 31. 余談 脱・副作用を追い求めた先に • 関数から「副作用」を取り除くと、関数の実行結果は引数だけ で説明がつく。 • =いつ・どこで実行してもいい。 • =関数の実行はその結果が本当に必要になったときまで先延ばしにし ておくことができる。 • =関数をその引数とともにキャッシュしておくことで、繰り返し実行 することが不要になる。 • =CPUおよびメモリリソースの使用を必要なとき・必要なだけに制限 できるようになる。 • 例: • HaskellのIOモナド(不気味なまでの参照透過性。ただし原理主義的過 ぎて窮屈なのも事実) • C#のPLINQやJavaのParallelStream(いつ・どこで実行してもいい ということは並列実行もできるということ)
  32. 32. テストしやすい条件 (十分条件)
  33. 33. ではUT可能となる条件とは? • テストできる条件 1. 公開されていること 2. 仕様がわかっていること(実装は不要) 3. 初期化ができること(cf. ASP.NET WebForm) 4. 「副作用」を制御できること(後述) 5. 条件が一定なら何度実行しても結果が変わらないこと • テストしやすい条件 1. 「副作用」がないこと(後述) 2. 初期化が簡単であること 3. 実行に時間がかからないこと 4. 依存するモジュールのモックを指定できること 再掲
  34. 34. 「しやすい」≒「できる」 • 繰り返しになるが、「テストが面倒」なプログラムは、時間の 限られた業務という実際上からすれば「テストが不可能」に近 しいものとなる。 • つまり「しやすい」≒「できる」。
  35. 35. テストしやすい条件: 3. 実行に時間がかからないこと • 実行に時間のかかるテストは、繰り返し実行できない。 • 繰り返し実行できないテストは、プログラムの変更の都度実行 できない(時間的リソースが無限にある場合は除く)。 • 変更の都度実行できないテストは、プログラムの変更をフォ ローアップできない。 • 変更をフォローアップできないテストは意味をなさない。 • 以上。
  36. 36. テストしやすい条件: 4. モックを指定できる • モック(mock)とは、テスト対象のオブジェクトが依存する オブジェクトの、その代役を務めるオブジェクト。 • 依存オブジェクトのモックを指定できないオブジェクトは、テ ストケースの検討が非常に難しくなる。
  37. 37. テストしやすい条件: 4. モックを指定できる • 例: • UserServiceはそのメソッドの中でUserDaoのメソッドを呼び出して いる。つまりUserServiceはUserDaoに依存している。 • UserServiceをテストするのに、UserDaoの挙動まで確認するのはテ ストを困難もしくは不可能にさせてしまう。 • したがって、テスト時はUserDaoのモック(例えばそのメソッドは必 ず同じ決まった値を返す)をUserServiceに設定しておき、 UserServiceのコードだけをテストできるように仕向ける。 IT~本番用 UT用
  38. 38. モックを指定できる条件 • テスト対象オブジェクトのコンストラクタやsetterを通じて依 存オブジェクトやそのモックを指定できること • =テスト対象オブジェクトのなかで、依存オブジェクトがnew演算子 で初期化されたりしていないこと • =依存オブジェクトのメソッドがstaticでないこと(あるインスタン スは交換できるが、クラスは交換できない※1) • とくに大規模なアプリでは、モックと非モック(IT~本番用) の切り替えをDIコンテナにより実行できること • Mockitoのような高機能なモック作成ライブラリがあればなお よい ※1 JavaでもC#でもstaticメソッドはサブクラスに継承されない。つまり「IUserServiceのメンバーとして宣言 しておいてUserServiceImplやUserServiceMockで実装をする」ということができない。よって交換が効かない。
  39. 39. モックを指定できる条件 • ちなみに・・・ • 某Hマネージャーの談「A_____刷新プロジェクトやってて思ったんだ けどさー、正直DIとかいらなくない?」 • その "こころ" は「あのプロジェクトはUT実施に関して完全に失敗し た。UTやらないんなら、DIコンテナなんて使わず、依存オブジェクト をnew演算子で初期化するほうが簡単」 • こんなときは・・・ • 「じゃぁ、しっかりUTやって、DIコンテナの存在理由ができるように しなくちゃいけませんね」と答えましょう※1。 ※1 もちろんDIコンテナにはAOPやトランザクションの制御の反転という役割もあるので、UTだけがその存在 理由ではないですが。
  40. 40. ここまで来たところで・・・ • UTにはいろいろと制約があることがわかった。 • では、これは「UTのための」制約なのだろうか? (UTのために背負い込まされる余計な負担なのだろうか?) • もちろん答えは「否」 1. 証明も反証できない命題は、良い悪いの問題以前の問題である。 UTがあろうとなかろうと(あるべきだが)、証明・反証可能なようにプログラム をつくる(工夫する)のは、要件にしたがってプログラムを書くプロとして当然 のこと。 2. とくに以下の項目は「正しくモジュール化され、仕様通りに動く、 バグの少ない、保守性のよいプログラム」のための方法論である: • 副作用の分離(≒参照透過性の確保) • 関心の分離 • 疎結合化(依存オブジェクトのインターフェース化、new演算子使用の抑制) この題目だけで、A___システムもB___システムも、既存のクラス は基本的に「手遅れ」であることがわかる。。
  41. 41. GetCurrentDateTime()のテスト • GetCurrentDateTime()のテスト • 既存コードのリファクタリング 作業
  42. 42. まとめ
  43. 43. まとめ • 今回は・・・ • UTできる条件・しやすい条件を確認した。 • UTしやすいAPIは正しくモジュール化されたAPIである点を確認した。 • 次回は・・・ • 実際の保守開発の中でUTを「どう活用」するかを考えてみる。 • TDDという開発スタイルの紹介 • CIツールによる自動テスト体制構築の手順説明

×