2013-10-09 3 views
8

ユニットテストされているオブジェクトをスパイするのはコードのにおいですか?たとえば、文字列内の行数を単純に数えることがジョブのクラスLineCounterを持っているとします。 -ユニットテストされているオブジェクト上のMockitoスパイリング

class LineCounter { 
    public int getNumLines(String string) { 
     String metadata = getStringMetadata(string); 

     // count lines in file 
     return numLines; 
    } 

    /** Expensive operation */ 
    protected String getStringMetadata(String string) { 
     // do stuff with string 
    } 
} 

今私は、この高価なgetStringMetadata呼び出しをあざけるながらgetNumLinesメソッドをテストするためのJUnit 4のテストを書きたいです。私はgetStringMetadataにダミー値を返すようにMockitoのスパイメカニズムを使うことに決めました。

class LineCounterTests { 
    @Test public void testGetNumLines() { 
     LineCounter lineCounterSpy = Mockito.spy(new LineCounter()); 

     // Mock out expensive call to return dummy value.    
     Mockito.when(lineCounterSpy.getStringMetadata(Mockito.anyString()).thenReturn("foo"); 

     assertEquals(2, lineCounterSpy.getNumLines("hello\nworld"); 
    } 
} 

これは妥当なことですか?実際のクラスではなくスパイオブジェクトをテストするのはとても奇妙だと思っていますが、実際にはそれに反対する理由は考えられません。

+4

コードの改善をテストする場合があります。これは、文字列メタデータを取得する作業が別のクラスに抽出されるべきであるように見えます。このクラスは、 'LineCounter'によって委譲されます。その時点で、あなたは "継ぎ目"を作り、より一般的な(そしてより臭いのない)方法でその依存関係を模倣することができます – millhouse

+0

@millhouseうん、それはそれを行う*正しい*方法のように見えることに全く賛成します。私は疑問に思っています、テストされているオブジェクトがスパイである私の例では本質的に何かが間違っていますか? – Matthew

答えて

3

私は2つの部分で質問に答えます。まず、はい、それは、テスト中のクラスを模擬するかスパイするためにコードのにおいです。それが正しく行えないことを意味するものではなく、危険性が高く、可能な限り避けるべきであるということです。

WRTあなたの具体的な例では、スパイが正しく使用される方法を見ていますが、これは完全にユニットテストされた別の場所にあることを前提にしていますgetStringMetadata。あなたが完全に単体テストのテストをしていれば、あなたはそれをテストする方法を知っていなければなりません。それで、スパイなしでgetNumLinesをテストしないのはなぜですか?

これはすべて、millhouseが良い点を示していますが、高価なコードをどこかで単体テストする必要があります。彼の提案は、高価なコードを分離し、それを一度しかテスト/運動する必要がないことを保証するための長い道のりです。

+0

'getStringMetadata'をどこかでテストしたとします。私はまだ 'getNumLines'をテストしたいのですが、私はすでにそのメソッドが期待どおりに動作することを知っているので、getStringMetadataへの高価な呼び出しを実行する必要はありません。 @ millhouseの提案は有効で、 'getStringMetadata'を別のクラスに分割するアプローチが好きですが、私の元の質問はまだ残っています。私の例には何か間違った*がありますか?あるいは、これはなぜ、 'getStringMetadata'を別のクラスに抽出し、' LineCounter'をより良い方法でテストする際にその依存関係を嘲笑するのでしょうか? – Matthew

+0

また、テスト中のクラスをスパイすることは危険があります。あなたはそれについて詳述できますか? – Matthew

+0

「コードの匂い」があるかどうか尋ねました。私はそれがそうすることを提案する。誰かがそれを見てすぐに、「待って、ここで何が起こっているのか」と思うでしょう。それは正しいことができないということを意味するものではありません。一般的には避けて、レビューアの注意を引くべきです。 –

0

この状況では、テスト対象のメソッドによって呼び出されたメソッドをスタブするのは完全に正当です。それは私が孤立してテストするために考えることができる唯一の方法です。テストの唯一の目的のために、それ自身のクラスに単一のメソッドを抽出する必要はありません。

しかし、スタブされた方法の副作用に注意してください。スタブされたメソッドに副作用がある場合、副作用をスタブする必要がある場合は、戻り値をスタブするだけでは不十分かもしれません。副作用が非常に複雑な状況では、それが原因である可能性もありますが、それはテスト対象のクラス自体の実装においてコードの匂いを示す可能性が非常に高いでしょう。

は、あなたの質問に答えるために、私はそれが簡単にそれため の理由を見つけるために見つけることが、ハード的な理由を見つけることに対してそれを。これは私が毎日使っているテクニックであり、実装を完全に分離して個別にテストされる小さなメソッドで分割するのに役立ちます。

関連する問題