2016-10-26 5 views
5

googlemockとC++での依存性注入を使って単体テストを行うのは難しいです。モックと依存性注入は、コードテストを大幅に簡素化しますが、仮想メソッドに大きく依存しています。他の言語のクラスはデフォルトで仮想メソッドを使用しますが、C++の場合はそうではありません。私はC + +を使用して低オーバーヘッドのパフォーマンス測定フレームワークを作成しているので、すべての単一のクラスをインターフェース(純粋な仮想メソッドあり)から継承することは望ましい選択肢ではありません。私は次のことを行うことができ、このクラスをテストするにはCockでの擬似と依存性注入

struct event_info { /* ... */ }; 

template<typename Event> 
class event_manager { 
public: 
    event_manager(const std::vector<event_info>& events) { 
    std::transform(begin(events), end(events), 
     std::back_inserter(events_), 
     [](const event_info& info) { return Event{info}; }); 
    } 

    void read() { 
    for (auto& e : events_) 
     e.read(); 
    } 

    // ... 

private: 
    std::vector<Event> events_; 
    // ... 
}; 

具体的には、私は、次の1などのオブジェクトのコレクションが含まれているテストクラスで問題を抱えている

class mock_event { 
public: 
    MOCK_METHOD0(read, void()); 
}; 

TEST(event_manager, test) { 
    event_manager<mock_event> manager; 
    // ... 
} 

しかし、 mockオブジェクトの期待値を設定することはできず、googlemockのモックオブジェクトはコピーできません(したがって、std::transformへの呼び出しはコンパイルに失敗します)。

この問題を解決するには、テスト時に代わりにポインタ(event_manager<mock_event*>)を使用して、event_managerコンストラクタにファクトリを渡します。しかし、これはe.read()のような呼び出しのためにコンパイルされません(テスト時にはe->read()になるはずです)。

次に、タイプ特性を使用して、参照が返されたばかりの参照が返され、ポインタが指定されている場合はポインタを逆参照します(dereference(e).read()など)。しかし、これはちょっとした複雑さを増やしてしまい、良い解決策のように見えません(特に、オブジェクトのコレクションを含むすべてのクラスをテストする必要がある場合)。

これはもっと良い解決策があるのだろうか、まさに擬似と依存性注入がC++にはあまり適していないということです。

+0

これは良い質問です!私は答えを期待する。私の理解では、 'event_manager'を少し修正しようとするかもしれません。' std :: vector > 'を使ってください。おそらくこれで問題は解決します。しかし、私はそれが動作するかどうかを確信していませんでした。 – Mine

+0

@Mine 'unique_ptr'とファクトリを使って(あるいは単にユーザが' unique_ptrを追加できるようにするためにインタフェースを変更するだけで ')動作するはずです。しかし、私は生産現場でポインタを格納する必要があります(テスト中だけでなく)。私はそれを避けるための解決策を探しています。 – betabandido

+0

うん、私はあなたが生産とテストコードの両方のポインタ( 'unique_ptr')ボットを格納できることを意味します。それは問題ではありません。 – Mine

答えて

1

仮想関数呼び出しを実行するためにポインタ参照解除のオーバーヘッドを許容できないと判断する前に、標準ユースケースをエミュレートする単純なクラスで適切なパフォーマンス測定を行ったとします。

gmockのドキュメントを読んだら、実動コードでテンプレートを使って仮想以外の機能を模擬する方法を示す「高性能模擬」セクションがあります。

私は、コード(生産またはテスト)の最初のルールはコードをできるだけシンプルに保つことだと思うので、テストすることができるようにテンプレートを使って生産コードを変更することは確信していません一方、私はTDDを批判として使用し、私の生産コードの設計を指導することに完全に有利です)。

このように、アプリケーションには、実行時ではなくリンク時にモックを実行できる別のモッキングフレームワークが必要なようです。

Cフリースタンディング関数とC++非仮想メソッドの両方をモックすることができるcpputestとcppumock(https://cpputest.github.io/)を調べてください。

cpputest/cppumockで支払う価格は、gmockよりも定規が必要ですが、非常に良いです。

+0

はい、いくつかの短い機能では、大きな違いがあります。私は確かにcpputestを見ます。 – betabandido