本文译自Unity/docs/UnityAssertionsReference.md,以及自己使用的总结。
Unity的官网:ThrowTheSwitch.org。
获取最新版本的Unity,可以访问:ThrowTheSwitch/Unity。
一、背景和概况
1.1 超浓缩概要
- 一条断言为单个条件确立真理(即True);如果为False,则报告失败并停止断言执行;
- Unity主要是一个丰富断言的集合,并且支持收集与执行这些断言;
- Unity的结构让你更加容易保持源代码与测试代码分离;
- Unity的断言:
- 有许多种不同风格以便处理不同的C类型和断言用例;
- 使用上下文提供详细和有用的失败消息;
- 免费为你的源码提供文档类型、期望值和基础行为。
1.2 Unity主要是断言
一种简单理解Unity的方法:++Unity是一个拥有丰富断言的集合,你可以用它来确定你的源代码是否按照你期望的方式运行++。Unity提供了一个框架,让你组织和执行这些断言,并保持与产品源码分离更加容易。
1.3 什么是断言
断言的核心是确立真理(布尔真),比如:
- 这个东西和那个东西相等/一样吗?
- 这段精妙的代码是否有这样、那样的属性?
断言是一些可执行代码(想了解更多信息,可查阅动态验证与静态分析的区别)。失败的断言会停止执行并通过适当的I/O通道报告一个错误(比如stdout、GUI、文件、闪灯)。
从根本上讲,对于动态验证,你只需要一个断言机制,而事实上,这是C标准库中assert()宏所作的事情。既然这样,我们为什么不直接使用assert()呢?因为我们在失败断言输出上做的更好,相比之下,C标准assert()的输出就像一个哑巴,特别是对于像数组、数据结构等通用类型。如果没有其他的支持,直接使用assert()实在太诱人了,但这通常会污染C源代码;而按照Unity的方式把测试代码和源码分开通常会更加干净、更易于管理,也更加有用。
1.4 Unity断言(有用的信息和免费的源码文档)
对简单的真值条件进行断言是非常有价值的,特别是断言失败的输出信息更有价值。比如,如果你知道当前比较的是位标志而不是整数,那么为什么不在断言失败时使用显示的、可读的、位等级的信息作为反馈呢?
这就是Unity做的事情:捕获源码上下文以提供有用的、有意义的断言失败信息。实际上,断言本身还可作为关于源代码中类型和值的可执行文档。只要您的测试与源代码保持同步,并且所有这些测试都通过了,你就可以对源代码中的意图和机制有一个详细的、实时更新的视图。由于奇妙的联系:能够良好通过测试的代码,通常也是经过良好设计的。
二、断言约定与配置
2.1 命名与参数约定
断言参数的约定一般遵循如下顺序:
TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} )
最简单的断言可能只使用一个“actual”参数(例如一个简单的null检查)。
- actual:将被测试的值;与断言构造的其他参数不同,它是唯一在所有断言变体中都存在的;
- modifiers:是掩码、范围、位标志说明符,或浮点增量;
- expected:是你期望值(duh),用于与actual值进行比较;它被标记为可选参数是因为:有些断言仅仅只需要一个‘actual’参数(比如NULL检查);
- size/count:指字符串长度,数组元素个数等。
Unity的许多断言是明显重复的:许多断言都拥有相同的数据类型,它们的区别是断言失败时的输出信息。比如:以‘_HEX’结束的断言变体在断言失败时将期望值与实际值按十六进制格式打印输出。
2.1.1 信息化断言变体(TEST_ASSERT_X_MESSAGE)
所有断言都有一个信息补充变体:++它接收一个字符串参数,并在断言失败时,将该字符串追加到断言失败信息后面一并输出++。
为了简明起见,这种带有一个字符串参数的断言变体不再本文列出,你只需要将‘_MESSAGE’作为末尾组件添加到本文列出的断言名称中,并添加一个字符串作为最后一个参数即可。比如:
TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} )
信息化后变成:
TEST_ASSERT_X_MESSAGE( {modifiers}, {expected}, actual, {size/count}, message )
【注意】:
- ‘_MESSAGE’信息化变体特意不支持printf风格的格式化的字符串参数,因为由于各种原因,许多嵌入式项目都不支持甚至避免使用‘printf’;如果需要的话,可以在断言之前使用‘sprintf’来组装复杂的失败信息;
- 如果你想在断言失败消息中输出计数器的值(比如在循环中),构建一个结果数组,然后使用‘_ARRAY’断言(见2.1.2 数组断言变体),就可以有效的避免使用‘sprintf’;
2.1.2 数组断言变体(TEST_ASSERT_X_ARRAY)
Unity为各种类型的数组提供了一个断言集合,本文的Array章节有详细描述(详见3.9 数组断言和3.10 分别相等断言)。与‘_MESSAGE’变体类似,你只需要在Unity绝大部分断言名称后面加上‘_ARRAY’,就可以在数组的整块内存中运行该断言了。
TEST_ASSERT_EQUAL_TYPEX_ARRAY( expected, actual, {size/count} )
- expected:是数组本身;
- size/count:必要的一个或两个参数,用于说明数组元素的个数,或者数组中单个元素的长度。
【注意】:
- ‘_MESSAGE’变体的约定仍能作用于array的断言上,‘_ARRAY’断言的‘_MESSAGE’变体的名字以‘_ARRAY_MESSAGE’结尾;
- 处理浮点值数组的‘_ARRAY’断言被分类到了float和double断言中(详见3.11 单精度浮点数断言和3.12 双精度浮点数断言)。
2.1.3 EACH_EQUAL断言变体(TEST_ASSERT_EACH_EQUAL_X)
Unity也为进行单值比较的、包含多种类型的数组提供了一个断言集合,后续章节的‘_EQUAL’部分都有详细介绍。同样与‘_MESSAGE’变体很像,你只需要在Unity绝大部分断言名称后面加上‘_EACH_EQUAL’,就可以在数组的