让咱们从修正承认中的代码开端。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 测验的成果如下:
那么,假如承认失利会发生什么?
咱们还没有针对失利案例的任何测验。咱们应该增加它们并使它们成为预期的失利,以便能够捕获行为。即使是失利也应该进行测验,以保证它仍然是失利。假如将来咱们对代码进行了一些更改,将失利转化为成功,那就太糟糕了。这将是一个重大更改,由于应该会失利。让咱们增加几个新的测验来承认。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);
}
咱们得到了预期的失利,它们看起来像这样:
下一步是设置预期的失利音讯,以便这些测验经过而不是失利。可是,有一个问题。行号是过错音讯的一部分。咱们期望行号显现在测验成果中。但这意味着咱们还有必要在预期的失利音讯中包含行号,以便将失利视为经过。为什么这是一个问题?嗯,这是由于每次移动测验时,乃至增加或删除其他测验时,行号都会更改。咱们不期望有必要为不属于过错的内容更改预期的过错音讯。行号告诉咱们过错发生的方位,不应是过错发生原因的一部分。
开启生长之旅!这是我参与「日新方案 2 月更文应战」的第 N 天,点击查看活动详情”