通过C ++中的合同和单元测试进行设计

时间:2012-11-20 00:27:53

标签: c++ unit-testing c++builder googletest design-by-contract

我正在尝试将基本的Design by Contract(由宏实现,它使用内置的assert函数)和Google Test unit测试结合在一个应用程序中。

因此,例如,我有以下代码:

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

    ...
}

现在,我的单元测试中无法进行以下测试,因为IDE在到达断言时中止(REQUIRE(!link.IsEmpty());):

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

所以,我的问题应该是:

  1. 永远不要测试合同所涵盖的条件,或
  2. 在单元测试期间以某种方式禁用合同检查?

2 个答案:

答案 0 :(得分:5)

您需要确定将空字符串传递给该函数是未定义的行为还是它的合同是否保证在传递空字符串时它会抛出异常。

听起来你的意图是它是未定义的行为,即合同没有说明如果传递空字符串会发生什么。在这种情况下,测试合同验证的最简单方法是将负面测试的单元测试构建为特殊构建,并修改REQUIRE以抛出一些“先决条件违反”异常,然后您将测试该异常ASSERT_THROW

我强烈建议您观看John Lakos' talk on Defensive Programming from ACCU 2011,它确实涵盖了这个问题

答案 1 :(得分:1)

合同设计定义了法律。您对软件的每次使用都必须遵守这些法律 - 包括其单元测试。单元测试测试,提供软件满足法律,它也做你想做的。

所以你应该只在满足前提条件的情况下测试你的软件。

在公共图层中,任何用户都可以以错误的方式使用它,最好让前置条件检查激活,或者使用特殊的输入验证层来保护您的输入,然后使用各种可能的输入数据对其进行测试,包括你的内部逻辑会认为违反前提条件的内容 - 但接下来你要测试的是保护层。

我发现遵循此策略的软件构建从长远来看更加强大和可维护。