Gtest:断言
一、前言
这篇文章主要参考 玩转Google开源C++单元测试框架Google Test系列(gtest)之二 - 断言 ,结合自己平时使用的Linux环境适当删减修改。
Assertion引发的三种结果
Assertions会引发3种结果:success、Non-Fatal Failure、Fatal Failure
Non-Fatal Failure 和 Fatal Failure啥区别?
前者失败后还会继续执行,后者失败后停止执行。ASSERT_* 系列的断言属于fatal assertion,EXPECT_* 系列的断言属于nonfatal assertion。
二、示例
#include <cstdio> #include <gtest/gtest.h> int Add(const int& a, const int& b) { return a + b; } namespace { TEST(AddTest, test_001) { EXPECT_EQ(4, Add(1 , 2)); } } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
假如你的Add(1, 2) 结果为4的话,会在结果中输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from AddTest [ RUN ] AddTest.test_001 /root/projects/Gtest_assertion/main.cpp:10: Failure Expected equality of these values: 4 Add(1 , 2) Which is: 3 [ FAILED ] AddTest.test_001 (0 ms) [----------] 1 test from AddTest (0 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. (1 ms total) [ PASSED ] 0 tests. [ FAILED ] 1 test, listed below: [ FAILED ] AddTest.test_001 1 FAILED TEST
如果是将结果输出到xml里的话,将输出:(关于将结果输出为xml,见:http://www.cnblogs.com/coderzh/archive/2009/04/10/1432789.html)
由于我使用的环境是VS2017远程连接Linux开发,所有代码最终还是在Linux上面,VS里面没有办法指定--gtest_output,我只能在Linux上面手动指定
Gtest_assertion.out --gtest_output="xml:report.xml"
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@1708 Debug]# cat report.xml <?xml version="1.0" encoding="UTF-8"?> <testsuites tests="1" failures="1" disabled="0" errors="0" timestamp="2019-01-05T19:36:28" time="0.001" name="AllTests"> <testsuite name="AddTest" tests="1" failures="1" disabled="0" errors="0" time="0.001"> <testcase name="test_001" status="run" time="0.001" classname="AddTest"> <failure message="/root/projects/Gtest_assertion/main.cpp:10 Expected equality of these values: 4 Add(1 , 2) Which is: 3" type=""><![CDATA[/root/projects/Gtest_assertion/main.cpp:10 Expected equality of these values: 4 Add(1 , 2) Which is: 3]]></failure> </testcase> </testsuite> </testsuites>
如果你对自动输出的出错信息不满意的话,你还可以通过操作符<<将一些自定义的信息输出,通常,这对于调试或是对一些检查点的补充说明来说,非常有用!
改进上面代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <gtest/gtest.h> int Add(const int& a, const int& b) { return a + b; } namespace { TEST(AddTest, test_001) { EXPECT_EQ(4, Add(1 , 2)) << "Add(1 , 2)= " << Add(1, 2); } } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
使用<<操作符将一些重要信息输出的话:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from AddTest [ RUN ] AddTest.test_001 /root/projects/Gtest_assertion/main.cpp:10: Failure Expected equality of these values: 4 Add(1 , 2) Which is: 3 Add(1 , 2)= 3 [ FAILED ] AddTest.test_001 (0 ms) [----------] 1 test from AddTest (0 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. (0 ms total) [ PASSED ] 0 tests. [ FAILED ] 1 test, listed below: [ FAILED ] AddTest.test_001 1 FAILED TEST
三、布尔值检查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
四、数值型数据检查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_EQ(expected, actual); | EXPECT_EQ(expected, actual); | expected == actual |
ASSERT_NE(val1, val2); | EXPECT_NE(val1, val2); | val1 != val2 |
ASSERT_LT(val1, val2); | EXPECT_LT(val1, val2); | val1 < val2 |
ASSERT_LE(val1, val2); | EXPECT_LE(val1, val2); | val1 <= val2 |
ASSERT_GT(val1, val2); | EXPECT_GT(val1, val2); | val1 > val2 |
ASSERT_GE(val1, val2); | EXPECT_GE(val1, val2); | val1 >= val2 |
五、字符串检查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_STREQ(expected_str, actual_str); | EXPECT_STREQ(expected_str, actual_str); | the two C strings have the same content |
ASSERT_STRNE(str1, str2); | EXPECT_STRNE(str1, str2); | the two C strings have different content |
ASSERT_STRCASEEQ(expected_str, actual_str); | EXPECT_STRCASEEQ(expected_str, actual_str); | the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1, str2); | EXPECT_STRCASENE(str1, str2); | the two C strings have different content, ignoring case |
*STREQ*和*STRNE*同时支持char*和wchar_t*类型的,*STRCASEEQ*和*STRCASENE*却只接收char*,估计是不常用吧。下面是几个例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
TEST(StringCmpTest, Demo) { char* pszCoderZh = "CoderZh"; wchar_t* wszCoderZh = L"CoderZh"; std::string strCoderZh = "CoderZh"; std::wstring wstrCoderZh = L"CoderZh"; EXPECT_STREQ("CoderZh", pszCoderZh); EXPECT_STREQ(L"CoderZh", wszCoderZh); EXPECT_STRNE("CnBlogs", pszCoderZh); EXPECT_STRNE(L"CnBlogs", wszCoderZh); EXPECT_STRCASEEQ("coderzh", pszCoderZh); //EXPECT_STRCASEEQ(L"coderzh", wszCoderZh); 不支持 EXPECT_STREQ("CoderZh", strCoderZh.c_str()); EXPECT_STREQ(L"CoderZh", wstrCoderZh.c_str()); }
六、显示返回成功或失败
这些断言实际上不测试值或表达式。 相反,它们直接产生成功或失败。 与实际执行测试的宏类似,您可以将自定义失败消息流入它们。
SUCCEED();
直接返回成功:
生成成功。 这不会使整体测试成功。 只有当测试在其执行期间没有任何断言失败时,测试才被认为是成功的。
注意:SUCCEED() is purely documentary,目前不生成任何用户可见的输出。 但是,我们可能会在未来向Google Test的输出中添加SUCCEED()消息
Fatal assertion | Nonfatal assertion | Nonfatal assertion |
FAIL(); | ADD_FAILURE(); | ADD_FAILURE_AT("file_path",line_number); |
FAIL()产生致命故障,而ADD_FAILURE()和ADD_FAILURE_AT()产生非致命故障。
如果用于控制流程而不是单纯判断boolean expression,这3个宏会很有用。代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
TEST(ExplicitTest, Demo) { ADD_FAILURE() << "Sorry"; // None Fatal Asserton,继续往下执行。 //FAIL(); // Fatal Assertion,不往下执行该案例。 SUCCEED(); }
注意:你只能在返回void的函数中使用FAIL()。 有关详细信息,请参阅 Assertion Placement section 部分。
七、异常断言
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_THROW(statement, exception_type); | EXPECT_THROW(statement, exception_type); | statement throws an exception of the given type |
ASSERT_ANY_THROW(statement); | EXPECT_ANY_THROW(statement); | statement throws an exception of any type |
ASSERT_NO_THROW(statement); | EXPECT_NO_THROW(statement); | statement doesn't throw any exception |
例如:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int Foo(int a, int b) { if (a == 0 || b == 0) { throw "don't do that"; } int c = a % b; if (c == 0) return b; return Foo(b, c); } TEST(FooTest, HandleZeroInput) { EXPECT_ANY_THROW(Foo(10, 0)); EXPECT_THROW(Foo(0, 5), char*); }
八、Predicate Assertions for Better Error Messages
尽管Google Test拥有丰富的断言,但它们永远不会完整,因为预测用户可能遇到的所有场景是不可能的(也不是一个好主意)。因此,有时用户必须使用EXPECT_TRUE()来检查复杂表达式,因为缺少更好的宏。这样做有个问题,EXPECT_TRUE()没有显示表达式部分的值,这使你很难理解出错的地方。作为一种解决方法,一些用户选择自己构造失败消息,将其流式传输到EXPECT_TRUE()。但是当表达式有副作用(side-effects)又或者计算费时 ,可能会导致某些奇怪问题。
Gtest提供了3种不同方式解决这个问题。
使用现有的布尔函数
如果你已经有一个function或functor返回bool(或一个可以隐式转换为bool的类型),你可以在谓词断言(predicate assertion)中不受任何限制的打印出函数参数。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_PRED1( pred1, val1); |
EXPECT_PRED1( pred1, val1); |
pred1(val1) returns true |
ASSERT_PRED2( pred2, val1, val2); |
EXPECT_PRED2( pred2, val1, val2); |
pred2(val1, val2) returns true |
... | ... | ... |
在上面,predn是一个n元predicate function 或 functor,,其中val1,val2,...和valn是它的参数。 如果谓词(predicate )在应用于给定参数时返回true,则断言成功,否则失败。 当断言失败时,它打印每个参数的值。 在任何一种情况下,参数只计算一次。
Here's an example:
//如果m和n没有除1之外的公约数,则返回true。 bool MutuallyPrime(int m, int n) { ... } const int a = 3; const int b = 4; const int c = 10;
断言EXPECT_PRED2(Mutual Prime,a,b); 将成功,而断言EXPECT_PRED2(MutuallyPrime,b,c); 将失败。
!MutuallyPrime(b, c) is false, where b is 4 c is 10
注意:
1. 如果在使用ASSERT_PRED *或EXPECT_PRED *时看到编译器错误“no matching function to call(无匹配函数调用)”,请参阅此常见问题解答 this FAQ 以了解如何解决它。
2. 目前我们只提供 <= 5个参数的的predicate assertions。
使用返回AssertionResult的函数
虽然EXPECT_PRED*() and friends对快速工作很方便,但是语法不令人满意:应对不同情况你必须使用不同的宏,它感觉更像Lisp而不是C ++。 :: testing :: AssertionResult类解决了这个问题。
AssertionResult对象表示断言的结果(无论它是成功还是失败,以及相关联的消息)。 您可以使用以下工厂函数之一创建AssertionResult:
namespace testing { // Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess(); // Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure(); }
你可以使用<<运算符将消息流式传输到AssertionResult对象。
要在布尔断言(例如EXPECT_TRUE())中提供更多可读消息,请编写一个返回AssertionResult而不是bool的谓词函数。 例如,如果您将IsEven()定义为:
::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << n << " is odd"; }
而不是
bool IsEven(int n) { return (n % 2) == 0; }
针对EXPECT_TRUE(IsEven(Fib(4)))错误的断言将要输出
Value of: IsEven(Fib(4)) Actual: false (*3 is odd*) Expected: true
而不是这种特别模糊的输出
Value of: IsEven(Fib(4)) Actual: false Expected: true
如果想要在EXPECT_FALSE and ASSERT_FALSE中也输出大量有用信息们可以这样做
::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess() << n << " is even"; else return ::testing::AssertionFailure() << n << " is odd"; }
EXPECT_FALSE(IsEven(Fib(6)))将会打印输出
Value of: IsEven(Fib(6)) Actual: true (8 is even) Expected: false
使用谓词格式化(Predicate-Formatter)
如果你发现由(ASSERT | EXPECT)_PRED *和(ASSERT | EXPECT)_(TRUE | FALSE)生成的默认消息不令人满意,或者您的predicate的某些参数不支持流到ostream,您可以使用以下predicate-formatter assertions来完全定义消息的格式:
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_PRED_FORMAT1( pred_format1, val1); |
EXPECT_PRED_FORMAT1( pred_format1, val1); |
pred_format1(val1) is successful |
ASSERT_PRED_FORMAT2( pred_format2, val1, val2); |
EXPECT_PRED_FORMAT2( pred_format2, val1, val2); |
pred_format2(val1, val2) is successful |
... |
... |
... |
这和(ASSERT | EXPECT)_PRED *宏的区别是,这一节讲的宏不是一个谓词,(ASSERT | EXPECT)_PRED_FORMAT *接收一个predicate-formatter(pred_formatn),它是一个函数或函数签名
::testing::AssertionResult PredicateFormattern(const char*expr1, const char*expr2, ... const char*exprn, T1 val1, T2 val2, ... Tn valn);
val1, val2, ..., 和valn 是predicate arguments的值。expr1, expr2, ..., 和 exprn是出现在代码中相应的表达式。T1, T2, ..., 和Tn可以试值类型,也可以是引用类型。举例来说,如果一个参数的类型是Foo,你把T*设置成Foo或const Foo&都可以。
predicate-formatter返回一个::testing::AssertionResult对象用于指明断言(assertion)成功与否,创建::testing::AssertionResult对象的唯一方式是使用下列工厂函数(factory functions)
一个例子,改善之前使用EXPECT_PRED2()那个例子的错误信息
// Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. ::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); }
借助predicate-formatter,我们可以使用
EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c);
会生成消息
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
事实上前面引入的许多断言都是(EXPECT|ASSERT)_PRED_FORMAT*的特例,他们中大多数也是使用(EXPECT|ASSERT)_PRED_FORMAT*.定义的。
九、浮点型检查
比较浮点数是棘手的。 由于舍入误差,两个浮点不太可能完全匹配。 因此,ASSERT_EQ的较傻的比较通常不起作用。 并且由于浮点可以具有宽的值范围,没有单个固定误差界限工作。 最好通过固定的相对误差界限进行比较,除了接近0的值由于精度的损失。
一般来说,对于浮点比较有意义,用户需要仔细选择误差界限。 如果他们不想要或关心,根据最后地点(ULP)中的单位进行比较是一个很好的默认值,Google测试提供了断言来做到这一点。 关于ULP的完整详细信息相当长; 如果你想了解更多,请参阅这篇关于浮动比较的文章 this article on float comparison.。
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_FLOAT_EQ(expected, actual); | EXPECT_FLOAT_EQ(expected, actual); | the two float values are almost equal |
ASSERT_DOUBLE_EQ(expected, actual); | EXPECT_DOUBLE_EQ(expected, actual); | the two double values are almost equal |
对相近的两个数比较:
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_NEAR(val1, val2, abs_error); | EXPECT_NEAR(val1, val2, abs_error); | the difference between val1 and val2 doesn't exceed the given absolute error |
同时,还可以使用:
EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);
十、Windows HRESULT assertions
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_HRESULT_SUCCEEDED(expression); | EXPECT_HRESULT_SUCCEEDED(expression); | expression is a success HRESULT |
ASSERT_HRESULT_FAILED(expression); | EXPECT_HRESULT_FAILED(expression); | expression is a failure HRESULT |
例如:
ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application"));
CComVariant empty;
ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty));
十一、类型断言
可以调用函数
::testing::StaticAssertTypeEq<T1, T2>();
来声称断言类型T1和T2是相同的。 如果满足断言,该函数不执行任何操作。 如果类型不同,函数调用将无法编译,编译器错误消息(取决于编译器)将显示T1和T2的实际值。 这主要在模板代码中有用。
注意:当在类模板或函数模板的成员函数中使用时,StaticAssertTypeEq <T1,T2>()仅在函数实例化时有效。 例如,给定:
template <typename T> class Foo { public: void Bar() { ::testing::StaticAssertTypeEq<int, T>(); } };
the code:
void Test1() { Foo<bool> foo; }
将不会生成编译器错误,因为Foo <bool> :: Bar()永远不会实际实例化。 相反,您需要:
void Test2() { Foo<bool> foo; foo.Bar(); }
导致编译器错误。
暂时用到的就这些,剩下的参考:
Gtest AdvancedGuide 对于国内译文 Google C++单元测试框架GoogleTest---AdvancedGuide(译文)上 (疑问有多处翻译bug,看的时候别全信)
其他文章:
专题: