web-dev-qa-db-ja.com

単体テスト+モック用にビルドシステムをセットアップする方法

完全にC++のレガシーコードベースがあります。ビルドシステムはCMakeです。単体テストでの最初の試みは次のとおりです。

  • ターゲットを定義します(LibraryA)。このライブラリには、テストするコードが含まれています。
  • テスト中のLibraryAのCPPテストファイルごとに単体テストターゲットを定義し、LibraryA.libに対してリンクします。

基本的に、ソース構造は次のようになります。

LibraryA/
  Source/
    Utils/
      MyClass.cpp
      MyClass.hpp
      AnotherClass.cpp
      AnotherClass.hpp
    Network/
      Socket.cpp
      Socket.hpp
  Tests/
    Utils/
      TestMyClass.cpp
      TestAnotherClass.cpp

ここにあるのは、Source内のTestsディレクトリのミラー構造です。この構造により、コンパイラコマンドラインレベルでインクルードオーダートリックを使用して、モック目的でクラスヘッダーが見つかる場所に優先順位を付けることができます。 Testsの下の各Test*.cppファイルは、1つの実行可能ファイルになります。したがって、テストされるクラスごとに1つの実行可能テスト。

問題は、テスト実行可能ファイルでLibraryA.libに対してリンクしていることです。 Socketクラスをモックしたい場合、LibraryA.libにはすでにシンボルがコンパイルされているため、これはODR違反になります。シンボルを複製せずにモックすることはできないので、リンカが文句を言うでしょう。

ユニットテスト構造の全体的な設定は、モックに関しては、ビルドシステムの観点から大きな問題でした。

この問題の良い解決策はありますか?テスト構造への私のアプローチは完全に間違っていますか?

6
void.pointer

2つのオプションがあります。

  • socketコンパイル済みバイナリをlibaryAにリンクせず、libraryAをモックでコンパイルします。これはあなたがやろうとしていることだと思います:リンク時依存性注入。
  • 実行時の依存性注入を使用します。 Socketクラスのインターフェースを追加し、ある種の依存性注入(ファクトリー、コンストラクター、またはメソッド)を使用します。テストでは、実際のSocketを注入する代わりに、モックを注入します。モックへの呼び出しをテストできるため、これはさらに優れています。

リンク時依存性注入(最初のオプション)は、リンク時にコードを注入することを意味します。

Socket.hがSockerクラスを宣言し、Socket.cppがそれを実装する場合は、同じ名前のSocketでモッククラスを定義するヘッダーを追加します。元のソケットと同じ名前空間にある必要があります。

次に、単体テストをビルドするときに、Socket.cppをコンパイルしてリンクしないでください。モッククラスをコンパイルしてリンクし、ユニットテストで使用する必要があります。

2
BЈовић

シンプル:ライブラリをモックし(.ccファイルと.hファイルの両方をモックします)、同じライブラリが異なるテストで異なる方法でモックされるように準備します。

1
zzz777