2

基本的な Design by Contract (組み込みの assert 関数を使用するマクロによって実装) と Google Test 単体テストをアプリケーションで組み合わせようとしています。

たとえば、次のコードがあります。

AppFavorite* AppFavorites::Add(const UnicodeString& link)
{
    REQUIRE(!link.IsEmpty());

    ...
}

アサート (REQUIRE(!link.IsEmpty());) に達すると IDE が中止されるため、単体テストで次のテストを行うことができません。

TEST(AppFavoritesTest, AddEmpty)
{
    AppFavorites favorites;
    ASSERT_THROW(favorites.Add(L""), std::invalid_argument);
}

だから、私の質問は、次のいずれかでなければならないということです:

  1. 契約でカバーされている条件をテストしないでください。
  2. 単体テスト中の契約チェックを何らかの形で無効にしますか?
4

2 に答える 2

5

その関数に空の文字列を渡すことが未定義の動作であるかどうか、または空の文字列が渡された場合に例外をスローすることが契約で保証されているかどうかを判断する必要があります。

あなたの意図は未定義の動作であるように思えます。つまり、空の文字列が渡された場合に何が起こるかについて、コントラクトは何も述べていません。REQUIREその場合、コントラクトの検証をテストする最も簡単な方法は、「前提条件違反」例外をスローするように変更された特別なビルドとして、ネガティブ テスト用のユニット テストをビルドすることです。ASSERT_THROW

ACCU 2011 の防御的プログラミングに関する John Lakos の講演を見ることを強くお勧めします。まさにこの問題をカバーしています。

于 2012-11-20T00:38:55.490 に答える
1

契約による設計は法律を定義します。ソフトウェアを使用するときはすべて、単体テストを含め、これらの法律に準拠する必要があります。単体テストは、ソフトウェアが法律を満たしていれば、あなたが望むことも実行することをテストします。

したがって、前提条件が満たされている場合にのみソフトウェアをテストする必要があります。

ユーザーが間違った方法で使用する可能性のあるパブリックレイヤーでは、前提条件チェックをアクティブのままにするか、特別な入力検証レイヤーで入力を保護することをお勧めします。このレイヤーは、内部ロジックは前提条件違反と見なされますが、テストするのは保護レイヤーです。

この戦略に従ったソフトウェアビルドは、長期的にははるかに堅牢で保守しやすいと思います。

于 2013-02-11T08:46:20.520 に答える