15

単体テストされているオブジェクトをスパイするのはコードの匂いですか? たとえばLineCounter、文字列の行数を単純にカウントするクラスがあるとします。--

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
    }
}

ここで、高価な呼び出しgetNumLinesをモックアウトしながらメソッドをテストするために、JUnit 4 テストを作成したいと考えています。getStringMetadataMockito のスパイ メカニズムを使用してgetStringMetadata、ダミーの値を返すことにしました。

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");
    }
}

これは合理的なことですか?実際のクラスではなく Spy オブジェクトをテストするのはかなり奇妙に感じますが、それに対する理由は本当に思いつきません。

4

2 に答える 2

4

2回に分けて質問にお答えします。まず、はい、テスト対象のクラスをモックまたはスパイするのはコードの匂いです。これは、正しく実行できないという意味ではありませんが、リスクが発生しやすいため、可能な限り回避する必要があります。

あなたの特定の例をWRTすると、スパイがどのように正しく使用されるかがわかりますが、それは他の場所で完全に単体テストされているという主張に基づいていますgetStringMetadata。他の場所で完全に単体テストを行っている場合は、それをテストする方法を知っている必要があるため、スパイなしでgetStringMetadataテストしてみませんか。getNumLines

これはすべてmillhouse、良い点ですが、いずれにせよ、高価なコードをどこかで単体テストする必要があります。彼の提案は、高価なコードを分離し、一度だけテスト/実行する必要があることを保証するのに大いに役立ちます.

于 2013-10-09T10:34:54.353 に答える
2

この状況では、テスト対象のメソッドによって呼び出されるメソッドをスタブすることは完全に正当です。それを単独でテストすることは、私が考えることができる唯一の方法です。テストのためだけに、単一のメソッドを独自のクラスに抽出したくないだけです。

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

あなたの質問に答えるために、その理由を見つけるのは簡単ですが、反対の理由を見つけるのは難しいと思います. これは私が毎日使用する手法です。実装を小さなメソッドに分割し、完全に分離して個別にテストするのに役立ちます。まだ制限はありません。

于 2016-03-15T07:52:34.233 に答える