Chapter 11.
Using Test Doubles
前回のまとめ
前回のまとめ
                                           設定可能?

Dummy   コンパイラを満足させるためだけに存在                   ×



Stub    テストから設定された値を SUT に返すために使う。           ○



Spy     SUT から値を受けとるために使う。SUT とのやりとりを覚え      ○
        ていて、テストは後で spy から聞き出す。


Mock    間接的入力/出力に使え、SUT とのやりとりを厳格にも寛容に       ○
        もすることができる。予想外のやりとりならすぐ失敗させるこ
        ともできる
Fake    テスト用に単純化された、 DOC の別実装。実際には DB に接     ×
        続に行かず、特定の値を返す Dao とか。
Providing the Test Double
●
    2 approaches
    ●
        Hand-Built Test Double
        –   Hard-Coded Test Double
        –   ちょっとがんばれば configurable になる
    ●
        Dynamically Generated Test Double
        –   基本的に Configurable Test Double
        –   jMock ファミリーが代表的 (←ちょっと情報が古い)
        –   EasyMock は少し毛色が違う
public void testDisplayCurrentTime_AtMidnight_PS() throws Exception {
  //Define and instantiate Test Stub
  TimeProvider testStub = new PseudoTimeProvider() { //Anonymous inner stub
    public Calendar getTime(String timeZone) {
      Calendar myTime = new GregorianCalendar();
      myTime.set(Calendar.MINUTE, 0);
      myTime.set(Calendar.HOUR_OF_DAY, 0);
      return myTime;
    }                
  };
  //Instantiate SUT
  TimeDisplay sut = new TimeDisplay();
  //Inject Test Stub into SUT
  sut.setTimeProvider(testStub);
  //Exercise SUT
  String result = sut.getCurrentTimeAsHtmlFragment();
  //Verify direct output
  String expectedTimeString = "<span class="tinyBoldText">Midnight</span>";
  assertEquals("Midnight", expectedTimeString, result);
}
Pseudo-Objects
●
    静的型付け言語で Hand-Coded な Double を
    作成するときには、 Pseudo-Object を作成し
    ておくと楽になる
    ●
        Inner Test Doubles や Self-Shunt につかう
Pseudo-Objects
/**
 * Base class for hand-coded Test Stubs and Mock Objects
 */
public class PseudoTimeProvider implements ComplexTimeProvider {

                       
    public Calendar getTime() throws TimeProviderEx {
      throw new PseudoClassException();
    }

    public Calendar getTimeDifference(Calendar baseTime,
                                      Calendar otherTime)
         throws TimeProviderEx {
      throw new PseudoClassException();
    }

    public Calendar getTime(String timeZone ) throws TimeProviderEx {
      throw new PseudoClassException();
    }
}
Configuring the Test Double
●
    Test Stub, Mock Object は何を返すか、何を話し
    かけられるかの設定行為が必要
    ●
        Hard-Coded Test Double の場合は設計時(コーディン
        グ時)に設定を行う
    ●
        Configurable Test Double はランタイムにテストから
        設定される
        –   Stub, Spy は何を返すかの設定が必要
        –   Mock は何を話しかけられるかの設定も加えて必要
●
    どういう値を選ぶかは設計行為そのもの
    ●
        テストの理解容易性
    ●
        Double の再利用性
Configuring the Test Double(2)
●
    Fake は SUT から使われるだけなのでランタイ
    ムに設定される必要なし
●
    Dummy は実行されないので設定の必要なし
●
    Procedual Test Stub は Hard-Coded の代表
    例
●
Configuring the Test Double(3)
●
    Configurable Test Double の設定方法
    ●
        Configuration Interface
    ●
        Configuration Mode
●
    利点
    ●
        テスト間での再利用性が高い
    ●
        値がテストコード内に書かれるので理解しやすい
        –   Mystery Guest アンチパターンを防ぐ
●
    設定場所は fixture setup と同じ扱い
Installing the Test Double
●
    “install” という言葉
●
    基本的な流れ
    ●
        Test Double のインスタンス化
    ●
        Configurable Test Double な場合は設定する
    ●
        「 Test Double を使え」とSUT の実行前か実行時
        に伝える
●
    “install” 方法は何種類かある
    ●
        種類の選択はテスト容易性の設計といえる
    ●
        選択の余地が無い場合も多いが、再設計もあるよ!
Installing the Test Double(2)
●
    基本的な選択肢は三つ
    ●
        Dependency Injection
    ●
        Dependency Lookup
    ●
        Test Hook
●
    IoC フレームワークが提供されている言語の場
    合にはいろいろ仕組みを自分で作らずに済む
Dependency Injection
●
    SUT が依存を自ら探すのではなく、誰かがラン
    タイムに外から設定する
●
    偽者を渡しやすいので TDD との相性◎
●
    依存性解決に関する知識が SUT から無くなる
    ので SUT の再利用性も大幅 UP
●
    3 types
    ●
        Setter Injection
    ●
        Constructor Injection
    ●
        Parameter Injection
Dependency Lookup
●
    テスト容易性を設計に組み込んでいなかった
    り、Dependency Injection の仕組みが言語に
    無い場合に使う
●
    SUT が誰かに DOC の作成を依頼する
    ●
        DOC の生成知識自体は SUT は持たない
    ●
        「誰か」は有名人になってしまう
●
    2 types (あまり違いは無い)
    ●
        Object Factory (GoF)
    ●
        Service Locator (PofEAA)
Test Specific Subclass
Test-Specific Subclass
●
    DI も DL も無くても、まだ諦めてはいけない
●
    介入可能な仕組みを組み上げてもがこう
    ●
        Singleton 死すべし
●
    DI 可能な仕組みを備えた、SUT のサブクラスを
    作成する
    ●
        テストに必要な部分に関して、 SUT のオーバーライ
        ドを行う
    ●
        でも SUT が non-private な self-call をする必要が
        ある
Test-Specific Subclass(2)
●
    DOC のサブクラスを作成する手もある
    ●
        Subclassed Test Double になる
    ●
        SUT のサブクラス作成よりは相対的に安全
Other Ways (最後の手段)
●
    Test Hooks
    ●
        Test Logic in Production
    ●
        レガシーコードからの第一手として
●
    さらなる手段は WEwLC にたくさんあるよ!
    ●
        Object Seam とか
    ●
        Dependency Breaking Technique の宝庫
        –   でも使わない状況になるのが一番幸せ
●
    AOP もある
ご清聴
ありがとう
ございました

xUnit Test Patterns - Chapter11

  • 1.
  • 2.
  • 3.
    前回のまとめ 設定可能? Dummy コンパイラを満足させるためだけに存在 × Stub テストから設定された値を SUT に返すために使う。 ○ Spy SUT から値を受けとるために使う。SUT とのやりとりを覚え ○ ていて、テストは後で spy から聞き出す。 Mock 間接的入力/出力に使え、SUT とのやりとりを厳格にも寛容に ○ もすることができる。予想外のやりとりならすぐ失敗させるこ ともできる Fake テスト用に単純化された、 DOC の別実装。実際には DB に接 × 続に行かず、特定の値を返す Dao とか。
  • 4.
    Providing the TestDouble ● 2 approaches ● Hand-Built Test Double – Hard-Coded Test Double – ちょっとがんばれば configurable になる ● Dynamically Generated Test Double – 基本的に Configurable Test Double – jMock ファミリーが代表的 (←ちょっと情報が古い) – EasyMock は少し毛色が違う
  • 5.
    public void testDisplayCurrentTime_AtMidnight_PS()throws Exception { //Define and instantiate Test Stub TimeProvider testStub = new PseudoTimeProvider() { //Anonymous inner stub public Calendar getTime(String timeZone) { Calendar myTime = new GregorianCalendar(); myTime.set(Calendar.MINUTE, 0); myTime.set(Calendar.HOUR_OF_DAY, 0); return myTime; }     }; //Instantiate SUT TimeDisplay sut = new TimeDisplay(); //Inject Test Stub into SUT sut.setTimeProvider(testStub); //Exercise SUT String result = sut.getCurrentTimeAsHtmlFragment(); //Verify direct output String expectedTimeString = "<span class="tinyBoldText">Midnight</span>"; assertEquals("Midnight", expectedTimeString, result); }
  • 6.
    Pseudo-Objects ● 静的型付け言語で Hand-Coded な Double を 作成するときには、 Pseudo-Object を作成し ておくと楽になる ● Inner Test Doubles や Self-Shunt につかう
  • 7.
    Pseudo-Objects /** * Baseclass for hand-coded Test Stubs and Mock Objects */ public class PseudoTimeProvider implements ComplexTimeProvider {     public Calendar getTime() throws TimeProviderEx { throw new PseudoClassException(); } public Calendar getTimeDifference(Calendar baseTime, Calendar otherTime) throws TimeProviderEx { throw new PseudoClassException(); } public Calendar getTime(String timeZone ) throws TimeProviderEx { throw new PseudoClassException(); } }
  • 8.
    Configuring the TestDouble ● Test Stub, Mock Object は何を返すか、何を話し かけられるかの設定行為が必要 ● Hard-Coded Test Double の場合は設計時(コーディン グ時)に設定を行う ● Configurable Test Double はランタイムにテストから 設定される – Stub, Spy は何を返すかの設定が必要 – Mock は何を話しかけられるかの設定も加えて必要 ● どういう値を選ぶかは設計行為そのもの ● テストの理解容易性 ● Double の再利用性
  • 9.
    Configuring the TestDouble(2) ● Fake は SUT から使われるだけなのでランタイ ムに設定される必要なし ● Dummy は実行されないので設定の必要なし ● Procedual Test Stub は Hard-Coded の代表 例 ●
  • 10.
    Configuring the TestDouble(3) ● Configurable Test Double の設定方法 ● Configuration Interface ● Configuration Mode ● 利点 ● テスト間での再利用性が高い ● 値がテストコード内に書かれるので理解しやすい – Mystery Guest アンチパターンを防ぐ ● 設定場所は fixture setup と同じ扱い
  • 11.
    Installing the TestDouble ● “install” という言葉 ● 基本的な流れ ● Test Double のインスタンス化 ● Configurable Test Double な場合は設定する ● 「 Test Double を使え」とSUT の実行前か実行時 に伝える ● “install” 方法は何種類かある ● 種類の選択はテスト容易性の設計といえる ● 選択の余地が無い場合も多いが、再設計もあるよ!
  • 12.
    Installing the TestDouble(2) ● 基本的な選択肢は三つ ● Dependency Injection ● Dependency Lookup ● Test Hook ● IoC フレームワークが提供されている言語の場 合にはいろいろ仕組みを自分で作らずに済む
  • 13.
    Dependency Injection ● SUT が依存を自ら探すのではなく、誰かがラン タイムに外から設定する ● 偽者を渡しやすいので TDD との相性◎ ● 依存性解決に関する知識が SUT から無くなる ので SUT の再利用性も大幅 UP ● 3 types ● Setter Injection ● Constructor Injection ● Parameter Injection
  • 14.
    Dependency Lookup ● テスト容易性を設計に組み込んでいなかった り、Dependency Injection の仕組みが言語に 無い場合に使う ● SUT が誰かに DOC の作成を依頼する ● DOC の生成知識自体は SUT は持たない ● 「誰か」は有名人になってしまう ● 2 types (あまり違いは無い) ● Object Factory (GoF) ● Service Locator (PofEAA)
  • 15.
  • 16.
    Test-Specific Subclass ● DI も DL も無くても、まだ諦めてはいけない ● 介入可能な仕組みを組み上げてもがこう ● Singleton 死すべし ● DI 可能な仕組みを備えた、SUT のサブクラスを 作成する ● テストに必要な部分に関して、 SUT のオーバーライ ドを行う ● でも SUT が non-private な self-call をする必要が ある
  • 17.
    Test-Specific Subclass(2) ● DOC のサブクラスを作成する手もある ● Subclassed Test Double になる ● SUT のサブクラス作成よりは相対的に安全
  • 18.
    Other Ways (最後の手段) ● Test Hooks ● Test Logic in Production ● レガシーコードからの第一手として ● さらなる手段は WEwLC にたくさんあるよ! ● Object Seam とか ● Dependency Breaking Technique の宝庫 – でも使わない状況になるのが一番幸せ ● AOP もある
  • 19.