Upgrade to Pro — share decks privately, control downloads, hide ads and more …

xUnit Test Patterns の序章

takattata
January 11, 2018

xUnit Test Patterns の序章

@社内LT大会_12月

※著作権的にアウトそうだったら消します

takattata

January 11, 2018
Tweet

More Decks by takattata

Other Decks in Technology

Transcript

  1. @takattata xUnit Test Patterns の序章

  2. xUnit xUnitって何があるかご存知ですか?

  3. JUnit(Java) SUnit(Smalltalk) NUnit(.Net) VbUnit(Visual Basic) CUnit(C) CppUnit(C++) PerlUnit(Perl) PyUnit(Python) HUnit(Haskell)

    HttpUnit(HTTPによる通信を擬似的に行なう ) HtmlUnit(ウェブブラウザのエミュレータ ) … xUnitでなくても、テストの体系を学べる本 xUnit
  4. Goals, Principles and Smells

  5. The Patterns

  6. 脆弱なテスト(Fragile Test)の問題 4つの点において限界があることを知るのは重要 Introduction: Fragile Test Problem

  7. Behavior Sensitivity システムの動作が変更された場合、修正された機能のテストは失敗する可能性が高い Introduction: Fragile Test Problem

  8. Interface Sensitivity UIを介してテスト中のシステム内のビジネスロジックをテストするのは良くない (過去よくあった?) Introduction: Fragile Test Problem

  9. Data Sensitivity テストは既にシステム内にあるデータの観点から定義された test fixture(=pre-conditions, before picture)があ るが、そのデータが変更された場合、多大な努力を払わないとテストは失敗する Introduction: Fragile

    Test Problem
  10. Context Sensitivity システム外の状態(デバイスや他アプリ, 日付等)のコンテキストの影響を受けるテストは、コンテキストを制御し ない限り、確定的に繰り返すことが困難 Introduction: Fragile Test Problem

  11. Behavior Sensitivity Interface Sensitivity Data Sensitivity Context Sensitivity →これらを解決する為には、テストのフレームワークを効果的に使用する方法を学ばないといけない Introduction:

    Fragile Test Problem
  12. 回帰テスト(regression testing) プログラムに手を加えたことによる影響を確認するテスト (=デグレしてないか確認する ) 仕様としてのテスト(tests as specification) TDD この本ではTDDの書き方ではなく、テストがどのようになっているかの観点から説明

    test-driven, test-first, test-last開発のどれでも役に立つので、「開発プロセスには無関心」で書いている Introduction: type
  13. Pattern =繰り返し問題に対する解決策 段階がある: 高いレベルの "strategy"パターン →より詳細な "design patterns" →最も詳細な "coding

    idioms" へと進むためには、パターン間にリンケージが必要 Introduction: Patterns
  14. Introduction: Patterns 3つのレベルで区別している - “Strategy” level patterns 大きな影響をもたらす Shared Fixture,

    Fresh Fixtureを使用することで異なるテストデザインパターンに繋がる - Test “Design” level patterns 特定の機能のテストを書く時, テストロジックをどう整理するかに焦点をあてる ex.) Mock Object patternとか - Test “Coding Idioms” 特定のテストをコーディングする方法, 言語固有のもの
  15. Introduction: Patterns vs Principles vs Smells Principles 選択したパターンはテスト自動化の”ゴール”(テスト自動化で望まれる結果が書かれている)に影響を受ける “ゴール”はパターンを良くすることについての信念体系を体系化する、多くの”原則”によってサポートされている(詳細 については該当の章を参照のこと)

    Smells 使ってるパターンが持ってる、起こしがちな問題など
  16. Introduction: Testing Terminology system under test(SUT) 「何をテストしているのか(whatever thing we are

    testing)」の略 - unit testsを書く時、テストするクラス、メソッドのこと - customer testsを書く時、アプリ全体か主要なサブシステムのこと
  17. - Unit Testは特定のテストに 関してのみSUT - Unit2 Testを見た時、Unit1 SUTはUnit2 SUTが使用する ため、dependend-on

    component(DOC)の役割を する Testing Terminology
  18. Refactoring A Test

  19. Why Refactor Tests? テストは迅速な開発プロセスのボトルネックになるので、リファクタリングをした方が良い 実際に複雑なテストを簡単にする流れを見ながら、生産性の違いを感じてほしい 途中でいくつか重要なsmellsや、それを取り除くためのパターンを出していくよ

  20. A Complex Test ・長い ・コメントが4行も ・ややこしい etc...

  21. test conditionsを見ていこう まずここ、必ずfalseになることを期待しているなら、 Cleaning up the Verification Logic

  22. 失敗の呼び出しに変更しよう!直接言うべき これはExtract Method [Fowler]リファクタリング (Martin FowlerのRefactoring Improving the Design of

    Existing Codeからメソッド名を引 用)
  23. 他にもある 何故こんなにアサーションが必要なんだ?

  24. 予想されるオブジェクトを作って、単一のアサーションを使おう これはPreserve Whole Object[Fowler] リファクタリング

  25. でも、待って! なんで if 文がテストに出てくるの? Conditional Test Logic は排除していこう 幸運にも、今回はGuard Assertionが使える

  26. if … else fail() … のところを同じ条件のアサーションに変えるだけ これをもっと短くしたいなら、 Extract Methodリファクタリングを使用して Custom

    Assertionを定義しよう こうなる ↓
  27. 良き! 次は finallyブロック に注目しよう

  28. そもそもこのコードには致命的な欠陥がある Cleaning up the Fixture Teardown Logic

  29. もしdeleteObjectで失敗したら?のテストがな い! とはいえ、右の様なテストを管理するのはあり 得ない! この問題にはComplex Teardownがある 問題の根本を解決することはできないが、 tearDownメソッドに入れてコードを細分化しよ う

  30. 案1: “テスト間で分割されない ”Shared Fixtureを 使うことで、最初にオブジェクトを作らなくて 良くなる が、問題が2つ 1. 共有されたfixtureを介してやり取りす ることで、Unrepeatable

    Test, Interacting Tests(不安定なテスト)を 含むtest smellsが多くなる 2. 共有されたfixtureから使われるオブ ジェクトへの参照がMystery Guests になる → 今回は却下
  31. 案2: Fresh Fixtureを使う 自動でGCされるメモリ内のfixtureを使う が、問題が1つ 1. 作成するオブジェクトが永続的なもの (DBに保存されているなど )では機能しな い

    → 今回は採用 実現方法: テスト自動化フレームワークに、作成したオブ ジェクトを登録する方法を追加して、削除する
  32. テストクラスに ・オブジェクトを確保しておくリスト ・追加する関数 ・削除する関数 を準備して、使う

  33. 良くなった が、まだいける たとえば、変数を初期化する必 要はあるだろうか? これはfinallyブロックのためだっ たから、宣言と初期化を合体さ せよう!

  34. None
  35. Cleaning up the Fixture Setup Extract Methodリファクタリングを使用してCreation Methodを定義しよう オブジェクトを作成して、registerTestObjectを呼び出す関数をそれぞれ作ろう 利点:

    読みやすくなる + カプセル化されるからコンストラクタが変更された時にメンテナンスしやすい
  36. まだ問題がいくつかある 1. fixtureが予想している結果とどう関連しているか分かりづらい 2. Hard-Coded Test Dataを使っている (Unrepeatable Test, Interacting

    Tests, Test Run Warが起こる可能性が出る ) 解決法: 各テストに固有の値を作って、その値を元にテスト用に作成したオブジェクトで使う (=Anonymous Creation Method) ←今までの引数は関数内に値を移した Addressも → customerで 使いたいだけ createACustomer関数 内でやれば良いね? (Extract Method再び)
  37. これで、テストで検証しているロジックに影響するものだけになった でも、まだ2回繰り返されているハードコーディングされたテストデータがある Replace Magic Number with Symbolic Constantリファクタリングで、 数字の意味を明確にしよう

  38. ついでに、計算が分かりにくいので Introduce Explaining Variableリファクタリングで文書化してみた このコードはTests as Documentationの役割を完全に満たしている(テストの”ゴール”に関わる) The Cleaned Up

    Test
  39. Writing More Tests Q: 毎度こんなに色々書くの ?? A: 再利用出来る Test Utility

    Methods があるし、 アプリのテストの為に Higher Level Language を定義している 「先ほどの内容をUtilityで書き 換えたけど、2分で書けたよ」