2011-07-08 19 views
12

現在、私のプロジェクトは様々な具体的なクラスで構成されています。単体テストに入ると、各クラスのインターフェイスを作成するはずです(実際にはプロジェクトのクラス数が倍増しています)。私は偶然フレームワークとしてGoogle Mockを使用しています。 Google Mock CookBook on Interfacesを参照してください。私が抽象クラス(別名C++インターフェイス)CarEngineを持っていて、次に実装クラスCarImplementationEngineImplまたはそれ以外のものを持っているとしたら、私はクラスCarEngineだけを持っていました。これは私にへのCarの依存を抜粋することを可能にするでしょう。ユニットテスト:インターフェイスへのコーディング?

は、私がこれを研究に遭遇した思考の2行があります。

  1. あなたが与えられた抽象化の複数の 実装および/またはで使用するための必要性を有することができる場合にのみインタフェースを使用公開されたAPI、 を使用してください。そうしないと、インターフェイスが不必要に作成されることはありません。

  2. ユニットテストスタブ/ しばしばを皮肉っ「他の実装」であるので、はい、あなたは intefacesを作成する必要があります。

ユニットテストでは、プロジェクト内の各クラスのインターフェイスを作成する必要がありますか? (私は簡単にテストできるようにインターフェイスを作成することに傾いています)

答えて

0

プロジェクト内のすべてのクラスのインターフェイスを作成する必要はありません。これは完全に設計上の決定です。私はそれがほとんどではないことがわかった。しばしばn-tierデザインでは、データアクセスとロジックの間のレイヤーを抽象化したいと思っています。テストに必要なインフラストラクチャがなくてもロジックをテストするのに役立つので、これに向けて作業すべきだと私は主張します。 dependency injection and IoCのような抽象化の方法では、このようなことをする必要があり、そのロジックをテストするのが簡単になります。

私はあなたが試しているものを調べ、エラーが最も発生しやすいと思われる領域に焦点を当てます。これは、インタフェースが必要かどうかを判断するのに役立ちます。

1

実装視認性に関する試験の二つのカテゴリーがある:ブラックボックステストとホワイトボックステスト

  • ブラックボックステストは、そのインタフェースを介して実装をテストし、その仕様に合わせ検証に焦点を当てています。

  • ホワイトボックステストテストの詳細については、である必要があります。は一般的に外部からアクセス可能である必要があります。この種のテストは、実装コンポーネントが意図したとおりに動作することを検証します。だから、その結果が壊れているかを把握しようとしている開発者を対象とし、主にされている、またはモジュラーアーキテクチャへのそれらの定義のフィット感によりあざけり、プロジェクト内のすべてのクラスがする必要があるということにはならないmantainance

を必要とします完全にモジュール化されていること。クラスのグループがお互いを知っているときに、そのラインを描画するのはまったく問題ない。彼らはグループとして、いくつかのファサードインタフェースクラスの覗き見から他のモジュールに提示することができます。しかし、このモジュールの中には、実装の詳細についての知識を持つホワイトボックスのテストドライバが必要です。したがって、この種のテストはであり、モックには適していません。

これからは、すべてのことをモックやインターフェイスにする必要はありません。ファサード・インターフェースを実装し、それらのモックを作成する上位レベルの設計コンポーネントを用意するだけです。それはあなたのモックテストが

は、むしろあなたが長いのに有益ではないだろうと思うの変更にツールの力あなたをさせるよりも、自分のニーズにツールを使用しようと言った私見を完済スイートスポットを与えますrun

+0

ありがとうございます。私はそれをgrokしようとしています。ホワイトボックステストはモックに適していないと言っていますか?私が単体テストを見ているのは、私が各コードユニットをテストしようとしていることです。たとえば、私は 'Car'をテストしたい、' Car'は 'Engine'クラスに依存します。 *統合テストではなく、* unit *テストを確実に行うために、 'Engine'クラスをモックする必要があります(私のモックされた' Engine'を使うために 'Car'を取得します) 。それ以外の場合、私は2つのクラスをテストしており、ユニットテストではなく統合テストを行っています。そして、 'Engine'クラスを簡単に模擬するためには、それがインタフェースである必要があるようです。 – User

+0

ここで唯一の違いは、*単位*が表すことです。通常、テスト対象のユニットはコンパイルユニットまたはクラスを表しますが、そのようにする必要はありません。たとえば、グラフクラスを作成すると、ノードとエッジが強く結合しているため、それらを孤立してテストするのは非常に意味がありません。ファサードインターフェイスにグラフモジュール全体をラップするだけで、他のモジュールがグラフの模擬表現とやりとりする必要があるときは、個々のクラスではなくグラフファサードをモックする(適切なファサードとして、APIレベルのノード整数またはid) – lurscher

+0

私は単体テストについて理解していますが、エッジクラスがノードクラスを使用する場合は、エッジクラスをテストするときにノードクラスをモックしたいと思います。なぜなら、2つの "ユニット"同時に。エッジクラスのテストが失敗した場合、本当に失敗したエッジまたはノードであるかどうかはわかりません。私は、あなたが統合テストについて話していることを呼ぶと思います(それはある程度のセマンティクスであることに気がつきます)。 – User

5

あなたにはいくつかの選択肢があると思います。あなたが言うように、一つの選択肢はインターフェースを作ることです。あなたがインターフェイスを導入するためのクラス

class Engine: 
{ 
public: 
    void start(){ }; 
}; 

class Car 
{ 
public: 
    void start() 
    { 
     // do car specific stuff 
     e_.start(); 

private: 
    Engine e; 
}; 

を持っていると言う - あなたは突然、あなたの車を作った - あなたがエンジンのみの1種類を持っている場合は、エンジン

を取るために車を変更する
class Car 
{ 
public: 
    Car(Engine* engine) : 
    e_(engine) 
    {} 

    void start() 
    { 
     // do car specific stuff 
     e_->start(); 

private: 
    Engine *e_; 
}; 

を持っているでしょうオブジェクトを使用するのが難しい(エンジンを作成する人、エンジンを所有する人)。車は部品が多いので、この問題は引き続き増加します。

個別の実装が必要な場合は、別の方法としてテンプレートを使用することができます。これにより、インタフェースが不要になります。あなたのモックで

class Car<type EngineType = Engine> 
{ 
public: 
    void start() 
    { 
     // do car specific stuff 
     e_.start(); 

private: 
    EngineType e; 
}; 

、あなたがして、特殊なエンジンを搭載した車を作成することができます。

Car<MockEngine> testEngine; 

もう一つ、別のアプローチを、それをテストすることができるようにするためにエンジンにメソッドを追加することであろう、のようなもの:

class Engine: 
{ 
public: 
    void start(); 
    bool hasStarted() const; 
}; 

次に、車にチェックメソッドを追加するか、車からテストに継承することができます。

class TestCar : public Car 
{ 
public: 
    bool hasEngineStarted() { return e_.hasStarted(); } 
}; 

これは、EngineをCarクラスのprivateからprotectedに変更する必要があります。

実際の状況によっては、どのソリューションが最適かによって異なります。また、各開発者は、コードが単体テストされるべきであると考える方法について、それぞれ独自の聖杯を持っています。私の個人的な見解はクライアント/顧客を念頭に置いておくことです。あなたのクライアント(おそらく、あなたのチームの他の開発者)が車を作り、エンジンについて気にしないと仮定しましょう。したがって私はエンジンの概念(私の図書館の内部のクラス)を公開したくないので、単体テストをテストすることができます。私はインターフェイスを作成せず、2つのクラスを一緒にテストすることを選択します(私が与えた3つ目のオプション)。

関連する問題