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
    の序章

    View Slide

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

    View Slide

  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

    View Slide

  4. Goals, Principles and Smells

    View Slide

  5. The Patterns

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  12. 回帰テスト(regression testing)
    プログラムに手を加えたことによる影響を確認するテスト (=デグレしてないか確認する )
    仕様としてのテスト(tests as specification)
    TDD
    この本ではTDDの書き方ではなく、テストがどのようになっているかの観点から説明
    test-driven, test-first, test-last開発のどれでも役に立つので、「開発プロセスには無関心」で書いている
    Introduction: type

    View Slide

  13. Pattern
    =繰り返し問題に対する解決策
    段階がある:
    高いレベルの "strategy"パターン
    →より詳細な "design patterns"
    →最も詳細な "coding idioms"
    へと進むためには、パターン間にリンケージが必要
    Introduction: Patterns

    View Slide

  14. Introduction: Patterns
    3つのレベルで区別している
    - “Strategy” level patterns
    大きな影響をもたらす
    Shared Fixture, Fresh Fixtureを使用することで異なるテストデザインパターンに繋がる
    - Test “Design” level patterns
    特定の機能のテストを書く時, テストロジックをどう整理するかに焦点をあてる
    ex.) Mock Object patternとか
    - Test “Coding Idioms”
    特定のテストをコーディングする方法, 言語固有のもの

    View Slide

  15. Introduction: Patterns vs Principles vs Smells
    Principles
    選択したパターンはテスト自動化の”ゴール”(テスト自動化で望まれる結果が書かれている)に影響を受ける
    “ゴール”はパターンを良くすることについての信念体系を体系化する、多くの”原則”によってサポートされている(詳細
    については該当の章を参照のこと)
    Smells
    使ってるパターンが持ってる、起こしがちな問題など

    View Slide

  16. Introduction: Testing Terminology
    system under test(SUT)
    「何をテストしているのか(whatever thing we are testing)」の略
    - unit testsを書く時、テストするクラス、メソッドのこと
    - customer testsを書く時、アプリ全体か主要なサブシステムのこと

    View Slide

  17. - Unit Testは特定のテストに
    関してのみSUT
    - Unit2 Testを見た時、Unit1
    SUTはUnit2 SUTが使用する
    ため、dependend-on
    component(DOC)の役割を
    する
    Testing Terminology

    View Slide

  18. Refactoring
    A
    Test

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. 失敗の呼び出しに変更しよう!直接言うべき
    これはExtract Method [Fowler]リファクタリング
    (Martin FowlerのRefactoring Improving the Design of Existing Codeからメソッド名を引
    用)

    View Slide

  23. 他にもある
    何故こんなにアサーションが必要なんだ?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  27. 良き!
    次は
    finallyブロック
    に注目しよう

    View Slide

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

    View Slide

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

    View Slide

  30. 案1:
    “テスト間で分割されない ”Shared Fixtureを
    使うことで、最初にオブジェクトを作らなくて
    良くなる
    が、問題が2つ
    1. 共有されたfixtureを介してやり取りす
    ることで、Unrepeatable Test,
    Interacting Tests(不安定なテスト)を
    含むtest smellsが多くなる
    2. 共有されたfixtureから使われるオブ
    ジェクトへの参照がMystery Guests
    になる
    → 今回は却下

    View Slide

  31. 案2:
    Fresh Fixtureを使う
    自動でGCされるメモリ内のfixtureを使う
    が、問題が1つ
    1. 作成するオブジェクトが永続的なもの
    (DBに保存されているなど )では機能しな

    → 今回は採用
    実現方法:
    テスト自動化フレームワークに、作成したオブ
    ジェクトを登録する方法を追加して、削除する

    View Slide

  32. テストクラスに
    ・オブジェクトを確保しておくリスト
    ・追加する関数
    ・削除する関数
    を準備して、使う

    View Slide

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

    View Slide

  34. View Slide

  35. Cleaning up the Fixture Setup
    Extract Methodリファクタリングを使用してCreation Methodを定義しよう
    オブジェクトを作成して、registerTestObjectを呼び出す関数をそれぞれ作ろう
    利点:
    読みやすくなる + カプセル化されるからコンストラクタが変更された時にメンテナンスしやすい

    View Slide

  36. まだ問題がいくつかある
    1. fixtureが予想している結果とどう関連しているか分かりづらい
    2. Hard-Coded Test Dataを使っている
    (Unrepeatable Test, Interacting Tests, Test Run Warが起こる可能性が出る )
    解決法: 各テストに固有の値を作って、その値を元にテスト用に作成したオブジェクトで使う
    (=Anonymous Creation Method)
    ←今までの引数は関数内に値を移した
    Addressも →
    customerで
    使いたいだけ
    createACustomer関数
    内でやれば良いね?
    (Extract Method再び)

    View Slide

  37. これで、テストで検証しているロジックに影響するものだけになった
    でも、まだ2回繰り返されているハードコーディングされたテストデータがある
    Replace Magic Number with Symbolic Constantリファクタリングで、
    数字の意味を明確にしよう

    View Slide

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

    View Slide

  39. Writing More Tests
    Q:
    毎度こんなに色々書くの ??
    A:
    再利用出来る
    Test Utility Methods
    があるし、
    アプリのテストの為に
    Higher Level Language
    を定義している
    「先ほどの内容をUtilityで書き
    換えたけど、2分で書けたよ」

    View Slide