5

2 つまたは 3 つの異なるソースからデータを収集し、結果を返すコードの長いメソッドがある場合。単体テストがしやすいようにリファクタリングするにはどうすればよいですか? このメソッドは Web サービスであり、クライアント コードから 1 回呼び出してすべてのデータを収集したいと考えています。

いくつかの部分を、よりテストしやすい小さなメソッドにリファクタリングできます。ただし、現在のメソッドは引き続きこれら 5 つのメソッドを呼び出すため、テストしにくいままです。Java をプログラミング言語と仮定すると、そのようなコードをテスト可能にするためのパターンはありますか?

4

2 に答える 2

5

これは非常に一般的なテストの問題であり、これに対して私が遭遇する最も一般的な解決策は、依存性注入を使用してデータを使用するコードからデータのソースを分離することです。これは、優れたテストをサポートするだけでなく、一般的に、外部データ ソースを操作する際の優れた戦略です (責任の適切な分離、統合ポイントの分離、コードの再利用の促進など、いくつかの理由があります)。

必要な変更は次のようになります。

  • データ ソースごとに、そのソースからのデータへのアクセス方法を定義するインターフェイスを作成し、データを返すコードを、これを実装する別のクラスに分解します。
  • 依存関係により、「長い」関数を含むクラスにデータ ソースが挿入されます。
  • 単体テストでは、各データ ソースのモック実装を挿入します。

これがどのようになるかを示すいくつかのコード例を次に示します。このコードは単なるパターンの例であることに注意してください。物事にはもっと適切な名前が必要になります。このパターンを研究し、依存性注入とモッキング (ユニット テスターの武器庫で最も強力な 2 つの武器) についてさらに学ぶことは価値があります。

データ ソース

public interface DataSourceOne {
    public Data getData();
}

public class DataSourceOneImpl implements DataSourceOne {
    public Data getData() {
        ...
        return data;
    }
}

public interface DataSourceTwo {
    public Data getData();
}

public class DataSourceTwoImpl implements DataSourceTwo {
    public Data getData() {
        ...
        return data;
    }
}

Long メソッドを持つクラス

public class ClassWithLongMethod {
    private DataSourceOne dataSourceOne;
    private DataSourceTwo dataSourceTwo;

    public ClassWithLongMethod(DataSourceOne dataSourceOne,
                               DataSourceTwo dataSourceTwo) {
        this.dataSourceOne = dataSourceOne;
        this.dataSourceTwo = dataSourceTwo;
    }

    public Result longMethod() {
        someData = dataSourceOne.getData();
        someMoreData = dataSourceTwo.getData();
        ...
        return result;
    }
}

単体テスト

import org.junit.Test;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ClassWithLongMethodTest {

    @Test
    public void testLongMethod() {

        // Create mocked data sources which return the data required by your test
        DataSourceOne dataSourceOne = mock(DataSourceOne.class);
        when(dataSourceOne.getData()).thenReturn(...);
        DataSourceTwo dataSourceTwo = mock(DataSourceTwo.class);
        when(dataSourceTwo.getData()).thenReturn(...);

        // Create the object under test using the mocked data sources
        ClassWithLongMethod sut = new ClassWithLongMethod(dataSourceOne,
                                                          dataSourceTwo);

        // Now you can unit test the long method in isolation from it's dependencies
        Result result = sut.longMethod();

        // Assertions on result
        ...
    }
}

構文上の誤りがあればご容赦 (および訂正) してください。最近はあまり Java を作成していません。

于 2013-07-18T08:06:57.097 に答える
0

「大きな」メソッドのテストは、小さなメソッドをモックできる統合テストのようになります。

「大きな」メソッドを 5 つの分離されたメソッドに分けることができる場合、「大きな」メソッドは、意味的/文脈的に意味のある分離されたメソッドのグループにさらに分割できます。

次に、「大きな」メソッドの分離されたメソッドのより大きなグループをモックできます。

于 2013-07-17T19:08:04.893 に答える