12

クラスがあるとします

class Inner {
  public:
    void doSomething();
};

class Outer {
  public:
    Outer(Inner *inner);  // Dependency injection.

    void callInner();
};

適切な単体テストでは、 のテストが必要ですInner。次に、完全なスタック/の代わりに追加された機能に対して単体テストを実行できるようにOuter、実数ではなく を使用するInnerテストを行う必要があります。MockInnerOuterOuterInner

そうするために、GoogletestInnerは次のような純粋な抽象クラス (インターフェース) に変えることを提案しているようです:

// Introduced merely for the sake of unit-testing.
struct InnerInterface {
  void doSomething() = 0;
};

// Used in production.
class Inner : public InnerInterface {
  public:
    /* override */ void doSomething();
};

// Used in unit-tests.
class MockInner : public InnerInterface {
  public:
    /* override */ void doSomething();
};

class Outer {
  public:
    Outer(Inner *inner);  // Dependency injection.

    void callInner();
};

したがって、製品コードでは、Outer(new Inner);を使用します。テスト中に、Outer(new MockInner).

わかった。理論的にはいいように思えますが、コード全体でこのアイデアを使い始めたとき、私はすべての異常なクラスに対して純粋な抽象クラスを作成していることに気付きました。不要な仮想ディスパッチのために低下するわずかなランタイム パフォーマンスを無視できるとしても、定型的なタイピングがたくさんあります。

別のアプローチは、次のようにテンプレートを使用することです。

class Inner {
  public:
    void doSomething();
};

class MockInner {
  public:
    void doSomething();
};

template<class I>
class Outer {
  public:
    Outer(I *inner);

    void callInner();
};

// In production, use
Outer<Inner> obj;

// In test, use
Outer<MockInner> test_obj;

これにより、ボイラーメッキと不要な仮想ディスパッチが回避されます。しかし、今ではコードベース全体がおかしなヘッダー ファイルに含まれているため、ソースの実装を隠すことができません (イライラするテンプレート コンパイル エラーと長いビルド時間への対処は言うまでもありません)。

これらの 2 つの方法、バーチャルとテンプレートは、適切な単体テストを行う唯一の方法ですか? 適切な単体テストを行うためのより良い方法はありますか?

適切な単体テストとは、各単体テストがそのユニットによって導入された機能のみをテストし、ユニットの依存関係もテストしないことを意味します。

4

2 に答える 2

6

実際には、テストされたクラスのすべての依存関係をモックアウトする必要はないと思います。作成、使用、または理解するのが複雑な場合は、はい. また、DB、ネットワーク、ファイルシステムなどの不要な外部リソースに直接依存している場合。

ただし、これらのいずれも問題にならない場合は、IMO のインスタンスを直接使用しても問題ありません。すでに単体テストを行っているため、期待どおりに機能し、より高レベルの単体テストに干渉しないことを合理的に確信できます。

個人的には、単体テストの純粋主義者によって設定された理想的なセットアップに固執するよりも、単体テストを実行し、シンプルでクリーンで保守可能な設計を好みます。

各ユニットテストは、そのユニットによって導入された機能のみをテストしますが、ユニットの依存関係もテストしません。

機能を使用することと機能テストすることは、2 つの非常に異なるものです。

于 2011-03-24T22:10:01.893 に答える
2

Inner でインスタンスを直接使用することも問題ないと思います。私の問題は、コードの一部ではない外部オブジェクトをモックすることです (静的ライブラリまたは DLL、場合によってはサードパーティによって提供されます)。私は、モック DLL またはライブラリを同じクラス名で書き直してから、テスト用に別の方法でリンクする傾向があります。「仮想」を追加するために外部依存関係のヘッダー ファイルを変更することは、私には受け入れられないようです。誰かがより良い解決策を持っていますか?

于 2011-09-20T00:09:06.427 に答える