4

私は TDD の大ファンで、最近の開発の大部分で TDD を使用しています。ただし、私が頻繁に遭遇する状況の 1 つは、次の (不自然な) 例のようなものです。

次のようなインターフェースがあるとします (Java で記述していますが、実際には、これはどの OO 言語にも当てはまります)。

public interface PathFinder {
    GraphNode[] getShortestPath(GraphNode start, GraphNode goal);

    int getShortestPathLength(GraphNode start, GraphNode goal);
}

ここで、このインターフェースの 3 つの実装を作成したいとします。DijkstraPathFinderそれらを 、DepthFirstPathFinder、および と呼びましょうAStarPathFinder

問題は、TDD を使用してこれら 3 つの実装をどのように開発するかということです。getShortestPath() と getShortestPathLength() の結果は 3 つの実装すべてで一貫している必要があるため、それらのパブリック インターフェイスは同じになります。おそらく、それぞれに同じテストを記述します。

私の選択は次のようです:

  1. PathFinder最初の実装をコーディングするときに、1 セットのテストを作成します。次に、他の 2 つの実装を「ブラインド」で記述し、それらがPathFinderテストに合格することを確認します。2 番目の 2 つの実装クラスの開発に TDD を使用していないため、これは正しくないようです。

  2. テストファーストの方法で各実装クラスを開発します。クラスごとに同じテストを書くことになるので、これは正しくないようです。

  3. 上記の 2 つの手法を組み合わせます。これで、インターフェイスに対する一連のテストと、各実装クラスに対する一連のテストができました。これは良いことですが、テストはすべて同じであり、良いことではありません。

これは、特に Strategy パターンを実装する場合には、かなり一般的な状況のように思えます。もちろん、実装間の違いは時間の複雑さだけではありません。他の人はこの状況をどのように処理しますか? 私が認識していないインターフェイスに対するテスト ファースト開発のパターンはありますか?

4

5 に答える 5

3

インターフェイスを実行するためのインターフェイス テストを記述し、実際の実装のためのより詳細なテストを記述します。インターフェイスベースの設計では、単体テストがそのインターフェイスの一種の「契約」仕様を形成する必要があるという事実について少し話します。Spec# が出てきたら、これを行うための言語サポートされた方法があるかもしれません。

厳密な戦略の実装であるこの特定のケースでは、インターフェイス テストで十分です。インターフェースが実装の機能のサブセットである場合は、インターフェースと実装の両方をテストします。たとえば、3 つのインターフェイスを実装するクラスを考えてみましょう。

編集:これは、インターフェイスの別の実装を後で追加するときに、クラスがインターフェイスのコントラクトを正しく実装していることを確認するためのテストが既にあるので便利です。これは、ISortingStrategy のような具体的なものから、IDisposable のような幅広いものまで機能します。

于 2009-02-13T02:17:02.980 に答える
2

インターフェイスに対してテストを作成し、実装ごとにそれらを再利用することに問題はありません。たとえば、-

public class TestPathFinder : TestClass
{
    public IPathFinder _pathFinder;
    public IGraphNode _startNode;
    public IGraphNode _goalNode;

    public TestPathFinder() : this(null,null,null) { }
    public TestPathFinder(IPathFinder ipf, 
        IGraphNode start, IGraphNode goal) : base()
    {
        _pathFinder = ipf;
        _startNode = start;
        _goalNode = goal;
    }
}

TestPathFinder tpfDijkstra = new TestPathFinder(
    new DijkstraPathFinder(), n1, nN);
tpfDijkstra.RunTests();

//etc. - factory optional

これは、アジャイル/TDD の原則に非常に沿った、最小限の労力のソリューションであると私は主張します。

于 2009-02-13T03:07:12.703 に答える
1

同様の機能を持つ新しいテストのテンプレートとして、テスト コードを再利用してもかまいません。テスト対象の特定のクラスによっては、異なるモック オブジェクトと期待値でそれらを作り直す必要がある場合があります。少なくとも、新しい実装を使用するにはそれらをリファクタリングする必要があります。ただし、1 つのテストを取得し、それを新しいクラス用に作り直してから、そのテストに合格するコードだけを作成するという TDD メソッドに従います。ただし、これにはさらに多くの訓練が必要になる場合があります。なぜなら、既に 1 つの実装を身につけており、間違いなく既に作成したコードの影響を受けるからです。

于 2009-02-13T03:10:22.773 に答える
1

2 番目の 2 つの実装クラスの開発に TDD を使用していないため、これは正しくないようです。

確かにそうです。

1 つを除くすべてのテストをコメントアウトすることから始めます。テストに合格したら、リファクタリングするか、別のテストのコメントを外します。

JTF

于 2009-02-13T07:14:09.753 に答える