web-dev-qa-db-ja.com

関数を仮想としてマークするのはいつですか?

私はコードの慣用的な方法を理解しようとしています。作成したコンポーネントの単体テストにgmockを使用しています。 Gmockは、モックできるようにするために仮想メソッドを必要としますが、私がモックしようとしているクラスには、モックアウトしたい非仮想メソッドがあります。

したがって、オプションは、メソッドを仮想としてマークするか、純粋な仮想メソッドでインターフェースを作成するかのいずれかです。コードをテストするためだけにどちらかを実行するので、どちらも理想的ではありません。 C++の世界では、通常どのようにアプローチしますか?

3
broun

設計またはテストが間違っています。

フレームワークを使用してモックを作成する代わりに、独自の派生クラスを作成して、この「モック」クラスを中心にテストを設計してください。非仮想メソッドをモックするという考えは意味をなさないことに気付くでしょう。仮想メソッドの考え方は、基本クラスがいくつかの機能を必要とし、その子がそれを提供することを期待するというものです。基本クラスがメソッドを仮想化しない場合は、子がそのメソッドの動作を変更することを期待していないことを意味します。そのため、クラスの不可欠な部分であり、そのようにテストする必要があります。非仮想メソッドをモックアウトすることは、基本クラスの動作全体をテストしていないことを意味します。

頭に浮かぶのは、これを実行するように強制することは、基本クラスに複数の責任があること、および非仮想クラスが実際には抽出されたクラスのAPIである複数のクラスに分離する必要があることです。

4
Euphoric

通常、クラスをvirtualとしてマークします。これは、なんらかの実装(関数自体を直接宣言するクラス内またはこのクラスを継承する子内のいずれか)に加えて、宣言でコントラクトを宣言する必要がある場合に、実装で満たす必要があります。

宣言は基本的に次のように述べています:これらの型のパラメーターのセットを提供してくれれば、この型の変数(return型)を返すことが保証されます。あなたは関数自体の中で何が起こるか気にする必要はありませんが、これらの型のいくつかのパラメーターを私に与えれば、これらはかなり確かです、あなたは私があなたに戻り型を返すことをかなり確信することができます。

これは、アプリケーションのピボットが期待どおりの動作を提供する宣言であるが、正確な動作ではない場合、抽象化と呼ばれます。インターフェース、または純粋な仮想メソッドのみを含むC++クラスのインターフェースは、まさにそれです。彼らは契約を定義しますが、実装を提供しません。

単体テストを行う場合、コードで必要なのは、virtual関数のみに依存することです。すでに動作をvirtualとして提供しているクラスの関数を定義するか、関数のインターフェイスを表すまったく新しいクラスに関数の宣言を抽出する(宣言を純粋仮想にする)ことにより、これを行うことができます。抽象クラスを作成し、プロジェクト全体でこの新しく作成された抽象クラスを使用します。

2
Andy

静的継承を使用して、テンプレート引数を介してオブジェクトを注入できます。次に、単体テストで、実際のオブジェクトではなく、モックオブジェクトを挿入します。

このようなもの :

struct A {
  void doThings() {
  }
};

struct MockA {
  MOCK_METHOD0(doThings, void());
};


template< typename doer >
struct B {
  void foo() {
    a.doThings();
  }

  doer a;
};

次に、アプリケーションで実際のクラスを使用します。

B< A > b;

ユニットテストでモックをテストします:

B< MockA > b;
1
BЈовић