22

Boost Test フレームワークを使用して C++ コードの単体テストを行っていますが、関数がアサートするかどうかをテストできるかどうか疑問に思っています。はい、少し奇妙に聞こえますが、ご了承ください。私の関数の多くは、エントリ時に入力パラメーターをチェックし、それらが無効かどうかをアサートします。これをテストすると便利です。例えば:

void MyFunction(int param)
{
    assert(param > 0); // param cannot be less than 1
    ...
}

私はこのようなことができるようにしたいと思います:

BOOST_CHECK_ASSERT(MyFunction(0), true);
BOOST_CHECK_ASSERT(MyFunction(-1), true);
BOOST_CHECK_ASSERT(MyFunction(1), false);
...

Boost Testを使用してスローされている例外を確認できるので、assertマジックもあるのだろうか...

4

6 に答える 6

14

同じ問題を抱えていたので、ドキュメント (およびコード) を掘り下げて、「解決策」を見つけました。

Boost UTF はboost::execution_monitor(で <boost/test/execution_monitor.hpp>) を使用します。これは、テスト実行中に発生する可能性のあるすべてをキャッチすることを目的として設計されています。assert が見つかると、 execution_monitor はそれをインターセプトしてスローしboost::execution_exceptionます。したがって、 を使用BOOST_REQUIRE_THROWすると、アサートの失敗をアサートできます。

それで:

#include <boost/test/unit_test.hpp>
#include <boost/test/execution_monitor.hpp>  // for execution_exception

BOOST_AUTO_TEST_CASE(case_1)
{
  BOOST_REQUIRE_THROW(function_w_failing_assert(),
                      boost::execution_exception);
}

トリックを行う必要があります。(わたしにはできる。)

ただし(または免責事項):

  • わたしにはできる。つまり、Windows XP では、MSVC 7.1、ブースト 1.41.0 です。セットアップに不適切または壊れている可能性があります。

  • Boost Test の作者の意図ではないかもしれません。(execution_monitorの目的のようですが)。

  • すべての形式の致命的なエラーを同じように扱います。あなたの主張以外の何かが失敗している可能性があります。この場合、ega メモリ破損のバグを見逃す可能性があり、失敗したアサートを見逃す可能性があります。

  • 将来のブースト バージョンでは壊れる可能性があります。

  • アサートが無効になり、アサートが防止するように設定されたコードが実行されるため、リリース構成で実行すると失敗することが予想されます。非常に未定義の動作が発生します。

  • msvc のリリース構成で、何らかのアサートのようなエラーまたはその他の致命的なエラーが発生した場合、それはキャッチされません。(execution_monitor のドキュメントを参照してください)。

  • assert を使用するかどうかはあなた次第です。私は彼らが好き。

見る:

また、Gennadiy Rozental (Boost Test の著者) に感謝します。

于 2009-11-20T19:50:50.960 に答える
9

私がチェックしたいエラーには、不変条件と実行時エラーの 2 種類があります。

不変条件とは、何があっても常に真であるべきものです。それらのために、私はアサートを使用します。あなたが私に与えている出力バッファのゼロポインタを私に渡してはいけません。これは単純明快なコードのバグです。デバッグ ビルドでは、アサートされ、修正する機会が与えられます。リテール ビルドでは、アクセス違反が発生し、ミニダンプ (少なくとも私のコードでは Windows) またはコアダンプ (Mac/unix) が生成されます。ゼロポインターの逆参照を処理するのに意味のcatchあることはできません。Windows ではcatch (...)、アクセス違反を抑制し、ユーザーに、既にひどく、ひどく間違っている場合でも、問題はないという誤った自信を与えることができます。

これが、一般的に C++ のコード臭であると私が考えるようになった理由の 1 つであり、コア ダンプを生成してアプリを丁寧に終了する直前に(または)catch (...)に存在すると考えることができる唯一の合理的な場所です。mainWinMain

実行時エラーは、「権限が原因でこのファイルを書き込めません」や「ディスクがいっぱいなので、このファイルを書き込めません」などです。これらの種類のエラーの場合、例外をスローすることは理にかなっています。ユーザーは、ディレクトリのアクセス許可を変更したり、ファイルを削除したり、ファイルを保存する別の場所を選択したりするなどの操作を実行できるからです。これらの実行時エラーは、ユーザーが修正できます。不変条件の違反は、ユーザーが修正することはできず、プログラマのみが修正できます。(2 つが同じ場合もありますが、通常は異なります。)

単体テストでは、コードが生成する可能性のある実行時エラー例外を強制的にスローする必要があります。テスト中のシステムが例外セーフであることを確認するために、共同作業者に例外を強制することもできます。

ただし、単体テストで不変条件に対してコードを強制的にアサートすることには価値があるとは思いません。

于 2009-07-19T17:01:42.590 に答える
7

私はそうは思わない。例外をスローする独自のアサートをいつでも作成し、その例外に対して BOOST_CHECK_NOTHROW() を使用できます。

于 2008-11-06T23:05:21.127 に答える
3

この質問といくつかの回答は、実行時エラー検出とバグ検出を混同していると思います。また、意図とメカニズムを混同します。

実行時エラーは、100% 正しいプログラムで発生する可能性があるものです。検出が必要であり、適切なレポートと処理が必要であり、テストする必要があります。バグも発生します。プログラマーの利便性のために、事前条件チェック、不変チェック、またはランダム アサートを使用してバグを早期に発見することをお勧めします。しかし、これはプログラマーのツールです。このエラー メッセージは通常のユーザーには意味がありません。また、適切に作成されたプログラムが決して渡さないデータに対して関数の動作をテストすることは合理的ではないように思われます。

意図とメカニズムに関しては、例外は魔法ではないことに注意してください。しばらく前に、Peter Dimov が Boost メーリング リストで (およそ)、「例外は非ローカル ジャンプ メカニズムに過ぎない」と述べました。そして、これは非常に真実です。内部エラーの後、修復前に何かが破損するリスクなしに続行できるアプリケーションがある場合は、C++ 例外をスローするカスタム アサートを実装できます。しかし、それによって意図が変わることはなく、アサートのテストがより合理的になることもありません。

于 2009-07-19T19:28:51.280 に答える
2

仕事で同じ問題に遭遇しました。私の解決策は、コンパイルフラグを使用することです。フラグ GROKUS_TESTABLE がオンの場合、GROKUS_ASSERT は例外になり、Boost を使用すると、例外をスローするコード パスをテストできます。GROKUS_TESTABLE がオフの場合、GROKUS_ASSERT は c++ assert() に変換されます。

#if GROKUS_TESTABLE
#define GROKUS_ASSERT ... // exception
#define GROKUS_CHECK_THROW    BOOST_CHECK_THROW
#else
#define GROKUS_ASSERT ... // assert
#define GROKUS_CHECK_THROW(statement, exception)  {}  // no-op
#endif

私の元々の動機は、デバッグを支援することでした。つまり、assert() はすばやくデバッグでき、gdb では例外をデバッグするのが難しいことがよくあります。私のコンパイル フラグは、デバッグ可能性とテスト可能性のバランスが取れているようです。

お役に立てれば

于 2011-07-26T22:24:29.260 に答える
0

申し訳ありませんが、問題を間違った方法で攻撃しています。

「アサート」は悪魔 (別名「C」) のスポーンであり、適切な例外がある言語では役に立ちません。例外のあるアサートのような機能を再実装する方がいいです。このようにして、実際にエラーを正しい方法で処理したり (適切なクリーンアップ手順を含む)、自由にエラーをトリガーしたり (単体テスト用) することができます。

さらに、コードが Windows で実行される場合、アサーションに失敗すると、デバッグ/中止/再試行を提供する役に立たないポップアップが表示されます。自動化された単体テストに適しています。

したがって、例外をスローする assert 関数を再コーディングしてください。ここに1つあります: abort()を使用せずにassert()を行うにはどうすればよいですか?

これをマクロでラップして、_ _FILE _ _ と _ _ LINE _ _ (デバッグに便利) を取得すれば完了です。

于 2008-11-06T23:24:42.273 に答える