如何使用布尔值确认平等

891 阅读7分钟

让我们从修复确认中的代码开始。CPP,使其不再指学校成绩。我们希望确认与布尔等类型一起使用。这就是为什么我们现在拥有的确认宏称为 CONFIRM TRUE 和 CONFIRM FALSE。宏名称中提到的 true 和 false 是预期值。此外,宏接受单个参数,即实际值。

与其进行关于及格分数的测试,不如让我们用这样的布尔值测试来代替它:

TEST("Test bool confirms")
{



bool result = isNegative(0);

CONFIRM_FALSE (result);

result = isNegative(-1);

CONFIRM_TRUE (result);

}

新测试很清楚它测试的内容,并且需要一个名为isNegat ive的新辅助函数,而不是以前的确定成绩是否通过的函数。我想要一些简单的东西,可以用来生成具有明显期望值的结果。isNegative 函数替换了之前的 isPassingGrade 函数,如下所示:

bool isNegative (int value)

{
return value < 0;
}

这是一个简单的更改,它删除了基于成绩的探索性代码,并为我们提供了现在适合测试库的内容。

确认平等

在某种程度上,布尔值确认了对相等性的测试。它们确保实际布尔值等于预期值。唯一的区别是CONFIRM_TRUE和CONFIRM_FALSE确认不需要接受预期值的参数。他们的预期价值隐含在他们的名字中。我们可以对布尔类型执行此操作,因为只有两个可能的值。

但是,假设我们要验证一个实际的 int 值等于1。我们真的需要一个叫做 CONFIRM1的宏吗?对于每个可能的32位整数,我们需要数十亿个宏,对于64位整数,甚至需要更多。使用这种方法,验证文本字符串以确保它们与预期值匹配将变得不可能。

相反,我们所需要做的就是修改其他类型的宏,使其同时接受预期值和实际值。如果这两个值不相等,那么宏应该导致测试失败,并提供一个适当的消息来解释预期的结果和实际收到的结果

宏不是为解析不同类型而设计的。它们只执行简单的文本替换。我们需要真正的 C + + 函数来正确处理我们将要检查的不同类型。此外,我们还可以更改现有的 bool 宏来调用函数,而不是直接在宏中定义代码:

#define CONFIRM FALSE( actual ) \

if (actual) \

{\



throw MereTDD: :BoolConfirmException(false, _LINE_}:\

}

#define CONFIRM TRUE( actual ) \

if (not actual)\

{ \

throw MereTDD::BoolConfirmException(true, _LINE_):\

}; 

我们需要做的是将 if 和 throw 语句移动到函数中。我们只需要一个函数来表示真和假,它看起来像这样:

inline void confirm (

	bool expected,

	bool actual,

	int line)
}

	if (actual != expected)
	{

		throw BoolConfirmException(expected, line);
	}

这个函数可以放在 TestBase 定义之前 MereTDD 命名空间中的 Test.h 中。该函数需要内联,不再需要用名称空间限定异常,因为它现在位于相同的名称空间中。

此外,您可以更好地看到,即使对于 bool 值,这也是一个相等的比较。函数进行检查以确保实际值等于预期值,如果不等于,则抛出异常。宏可以简化为这样调用新函数:

#define CONFIRM_FALSE( actual ) \

	MereTDD::confirm (false, actual,_LINE_) 

#define CONFIRM_TRUE( actual ) \

	MereTDD:: confirm(true, actual, _LINE_)

构建和运行表明所有测试都通过,我们已准备好添加其他类型进行确认。让我们从确认中的新测试开始。像这样的整数类型的 CPP:

TEST("Test int confirms")

{
    int result = multiplyBy2 (0);

    CONFIRM(0, result);

    result = multiplyBy2(1);

    CONFIRM(2, result);

    result = multiplyBy2(-1);

    CONFIRM(—2, result) ;
}

此代码不是布尔值,而是测试 int 值。它使用一个新的帮助程序函数,该函数应该易于理解,只需将值乘以 2。我们需要在同一文件的顶部声明新的帮助程序函数,如下所示:

int multiplyBy2 (int value)
{
return value *2;
}

测试尚未生成。没关系,因为在使用 TDD 方法时,我们希望首先关注使用情况。这种用法似乎很好。它将让我们确认任何 int 值都等于我们期望的值。让我们创建 CONFIRM 宏,并将其放在确认 true 和 false 的两个现有宏之后,如下所示:

#define CONFIRM FALSE( actual ) \ 

    MereTDD::confirm(false, actual,__LINE__) 

#define CONFIRM TRUE( actual ) \

    MereTDD:: confirm(true, actual,__LINE__) 

#define CONFIRM( expected, actual ) \

    MereTDD::confirm(expected, actual,__LINE__)

更改宏以调用函数现在确实得到了回报。coNFIRM 宏需要一个额外的参数来表示期望值,并且可以调用相同的函数名称。但是,它如何调用相同的函数?嗯,那是因为我们要重载函数。我们现在所拥有的仅适用于布尔值。这就是我们切换到可以使用数据类型的设计的原因。我们需要做的就是提供另一个 confirm 实现,该实现已重载以处理如下所示的整数

inline void confirm (

	int expected,

	int actual,

	int line)

if (actual != expected){

            throw ActualConfirmException(expected, actual, line);
	}
}

这与现有的确认功能几乎相同。它接受int作为预期的和实际的参数而不是bool,并将抛出一个新的异常类型。使用新异常类型的原因是,我们可以格式化一个同时显示预期值和实际值的失败消息。BoolConfirmException类型将仅用于bool,并将格式化仅提及预期内容的消息。此外,新的ActualConfirmException类型将格式化一条同时提到预期值和实际值的消息。

您可能想知道为什么新的异常类型将预期值和实际值存储为字符串。构造函数接受 int,然后在格式化原因之前将 int 转换为字符串。这是因为我们将添加多个数据类型,并且我们实际上不需要做任何不同的事情。当测试失败时,每种类型只需要显示一个基于字符串的描述性消息。

任何计算都不需要使用期望值或实际值。它们只需要被格式化成一个可读的信息。此外,这种设计还允许我们对除 bool 之外的所有数据类型使用单个异常。我们也可以对 bools 使用这个新的异常,但是消息不需要提到 bools 的实际值。因此,我们将保留现有的针对 bools 的异常,并将这种新的异常类型用于其他所有内容

通过将预期值和实际值存储为字符串,我们所需要的就是为每个希望支持的新数据类型提供一个重载构造函数。每个构造函数都可以将预期值和实际值转换为字符串,然后将这些字符串格式化为可读的消息。这比有一个 Int斩获确认异常类、一个 String斩获确认异常类等要好得多。

我们可以重新构建并运行测试,bool 和 int 测试的结果如下:

ا

image.png

那么,如果确认失败会发生什么?

我们还没有针对失败案例的任何测试。我们应该添加它们并使它们成为预期的失败,以便可以捕获行为。即使是失败也应该进行测试,以确保它仍然是失败。如果将来我们对代码进行了一些更改,将失败转化为成功,那就太糟糕了。这将是一个重大更改,因为应该会失败。让我们添加几个新的测试来确认。CPP 像这样:

TEST("Test bool confirm failure")

{
    bool result = isNegative(0);

    CONFIRM TRUE (result);
}
TEST("Test int confirm failure")
{

    int result = multiplyBy2(1);

    CONFIRM(0, result);
}

我们得到了预期的失败,它们看起来像这样:

image.png

下一步是设置预期的失败消息,以便这些测试通过而不是失败。但是,有一个问题。行号是错误消息的一部分。我们希望行号显示在测试结果中。但这意味着我们还必须在预期的失败消息中包含行号,以便将失败视为通过。为什么这是一个问题?嗯,这是因为每次移动测试时,甚至添加或删除其他测试时,行号都会更改。我们不希望必须为不属于错误的内容更改预期的错误消息。行号告诉我们错误发生的位置,不应是错误发生原因的一部分。


开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情