20

これまで、即席の単体テスト手順を使用してきました。基本的には、バッチ ファイルによって自動的に実行される単体テスト プログラムの全負荷です。これらの多くは結果を明示的にチェックしますが、より多くの不正行為があります - バージョン管理されたテキスト ファイルに結果をダンプします。テスト結果の変更は、Subversion によってフラグが付けられ、変更内容を簡単に特定できます。テストの多くは、出力を視覚的に表現できるように、ドット ファイルまたはその他の形式で出力します。

問題は、cmake の使用に切り替えていることです。cmake フローを使用するということは、アウト オブ ソース ビルドを使用することを意味します。つまり、結果を共有ソース/ビルド フォルダーにダンプし、それらをソースと一緒にバージョン管理するという利便性は実際には機能しません。

代わりに、期待される結果のファイル (ソース ツリー内) を見つける場所を単体テスト ツールに指示し、比較を行うようにします失敗した場合は、実際の結果と差分リストを提供する必要があります。

これは可能ですか、それともまったく別のアプローチを取る必要がありますか?

明らかに、ctest を無視して、私が常に行ってきたことをアウト オブ ソース ビルドに適応させることができます。たとえば、すべてのビルドがライブであるフォルダーをバージョン管理できます (もちろん、「無視」を自由に使用して)。それは正気ですか?おそらくそうではありません。ビルドごとに、期待される結果の個別のコピーが作成されるためです。

また、cmake/ctest を使用して単体テストを行うための推奨される方法についてのアドバイスもありがたく受け取りました。cmake が悪いからではなく、cmake の最適な操作方法を理解していなかったために、cmake でかなりの時間を無駄にしました。

編集

最終的に、単体テストの cmake/ctest 側をできるだけシンプルに保つことにしました。期待される結果に対して実際の結果をテストするために、ライブラリで次の関数のホームを見つけました...

bool Check_Results (std::ostream              &p_Stream  ,
                    const char                *p_Title   ,
                    const char               **p_Expected,
                    const std::ostringstream  &p_Actual   )
{
  std::ostringstream l_Expected_Stream;

  while (*p_Expected != 0)
  {
    l_Expected_Stream << (*p_Expected) << std::endl;
    p_Expected++;
  }

  std::string l_Expected (l_Expected_Stream.str ());
  std::string l_Actual   (p_Actual.str ());

  bool l_Pass = (l_Actual == l_Expected);

  p_Stream << "Test: " << p_Title << " : ";

  if (l_Pass)
  {
    p_Stream << "Pass" << std::endl;
  }
  else
  {
    p_Stream << "*** FAIL ***" << std::endl;
    p_Stream << "===============================================================================" << std::endl;
    p_Stream << "Expected Results For: " << p_Title << std::endl;
    p_Stream << "-------------------------------------------------------------------------------" << std::endl;
    p_Stream << l_Expected;
    p_Stream << "===============================================================================" << std::endl;
    p_Stream << "Actual Results For: " << p_Title << std::endl;
    p_Stream << "-------------------------------------------------------------------------------" << std::endl;
    p_Stream << l_Actual;
    p_Stream << "===============================================================================" << std::endl;
  }

  return l_Pass;
}

典型的な単体テストは次のようになります...

bool Test0001 ()
{
  std::ostringstream l_Actual;

  const char* l_Expected [] =
  {
    "Some",
    "Expected",
    "Results",
    0
  };

  l_Actual << "Some" << std::endl
           << "Actual" << std::endl
           << "Results" << std::endl;

  return Check_Results (std::cout, "0001 - not a sane test", l_Expected, l_Actual);
}

再利用可能なデータ ダンプ関数が必要な場合は、 type のパラメーターを使用するstd::ostream&ため、実際の結果ストリームにダンプできます。

4

1 に答える 1

19

CMake のスタンドアロン スクリプト モードを使用してテストを実行し、出力を比較します。通常、単体テスト プログラムの場合は と記述add_test(testname testexecutable)しますが、任意のコマンドをテストとして実行できます。

スクリプト「runtest.cmake」を作成し、これを介して単体テスト プログラムを実行すると、runtest.cmake スクリプトは、cmake -E compare_filesユーティリティの使用を含め、好きなことを実行できます。CMakeLists.txt ファイルに次のようなものが必要です。

enable_testing()
add_executable(testprog main.c)
add_test(NAME runtestprog
    COMMAND ${CMAKE_COMMAND}
    -DTEST_PROG=$<TARGET_FILE:testprog>
    -DSOURCEDIR=${CMAKE_CURRENT_SOURCE_DIR}
    -P ${CMAKE_CURRENT_SOURCE_DIR}/runtest.cmake)

これにより、スクリプト (cmake -P runtest.cmake) が実行され、テスト実行可能ファイルのパスに設定された TEST_PROG と、現在のソース ディレクトリに設定された SOURCEDIR の 2 つの変数が定義されます。最初に実行するプログラムを知る必要があり、2 番目に期待されるテスト結果ファイルの場所を知る必要があります。の内容は次のruntest.cmakeようになります。

execute_process(COMMAND ${TEST_PROG}
                RESULT_VARIABLE HAD_ERROR)
if(HAD_ERROR)
    message(FATAL_ERROR "Test failed")
endif()

execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
    output.txt ${SOURCEDIR}/expected.txt
    RESULT_VARIABLE DIFFERENT)
if(DIFFERENT)
    message(FATAL_ERROR "Test failed - files differ")
endif()

最初execute_processに、"output.txt" を書き出すテスト プログラムを実行します。それが機能する場合、次はexecute_process効果的に実行されcmake -E compare_files output.txt expected.txtます。ファイル「expected.txt」は、ソース ツリーで既知の良好な結果です。違いがある場合はエラーが発生するため、失敗したテストを確認できます。

これが行わないのは、違いを出力することです。CMake には、完全な「差分」実装が隠されているわけではありません。現時点では、どの行が変更されたかを確認するために Subversion を使用しているため、明らかな解決策は最後の部分を次のように変更することです。

if(DIFFERENT)
    configure_file(output.txt ${SOURCEDIR}/expected.txt COPYONLY)
    execute_process(COMMAND svn diff ${SOURCEDIR}/expected.txt)
    message(FATAL_ERROR "Test failed - files differ")
endif()

これにより、失敗時にビルド出力でソース ツリーが上書きされ、その上で svn diff が実行されます。問題は、この方法でソース ツリーを実際に変更するべきではないということです。もう一度テストを実行すると、合格です! より良い方法は、視覚的な差分ツールをインストールし、それを出力と期待されるファイルで実行することです。

于 2010-07-22T12:43:41.050 に答える