一、前言
这篇文章主要参考 玩转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的话,会在结果中输出:
[==========] 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"
[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>
如果你对自动输出的出错信息不满意的话,你还可以通过操作符<<将一些自定义的信息输出,通常,这对于调试或是对一些检查点的补充说明来说,非常有用!
改进上面代码
#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(); }
使用<<操作符将一些重要信息输出的话:
[==========] 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*,估计是不常用吧。下面是几个例子:
{
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();
返回失败:
Fatal assertion | Nonfatal assertion |
FAIL(); | ADD_FAILURE(); |
{
ADD_FAILURE() << "Sorry"; // None Fatal Asserton,继续往下执行。
//FAIL(); // Fatal Assertion,不往下执行该案例。
SUCCEED();
}
七、异常检查
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 |
例如:
{
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
在使用EXPECT_TRUE或ASSERT_TRUE时,有时希望能够输出更加详细的信息,比如检查一个函数的返回值TRUE还是FALSE时,希望能够输出传入的参数是什么,以便失败后好跟踪。因此提供了如下的断言:
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 |
... | ... | ... |
Google人说了,他们只提供<=5个参数的,如果需要测试更多的参数,直接告诉他们。下面看看这个东西怎么用。
{
return Foo(m , n) > 1;
}
TEST(PredicateAssertionTest, Demo)
{
int m = 5, n = 6;
EXPECT_PRED2(MutuallyPrime, m, n);
}
当失败时,返回错误信息:
error: MutuallyPrime(m, n) evaluates to false, where
m evaluates to 5
n evaluates to 6
如果对这样的输出不满意的话,还可以自定义输出格式,通过如下:
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 |
... | ... |
用法示例:
if (Foo(m, n) == k)
return testing::AssertionSuccess();
testing::Message msg;
msg << m_expr << " 和 " << n_expr << " 的最大公约数应该是:" << Foo(m, n) << " 而不是:" << k_expr;
return testing::AssertionFailure(msg);
}
TEST(AssertFooTest, HandleFail)
{
EXPECT_PRED_FORMAT3(AssertFoo, 3, 6, 2);
}
失败时,输出信息:
error: 3 和 6 的最大公约数应该是:3 而不是:2
是不是更温馨呢,呵呵。
九、浮点型检查
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));
十一、类型检查
类型检查失败时,直接导致代码编不过,难得用处就在这?看下面的例子:
public:
void Bar() { testing::StaticAssertTypeEq<int, T>(); }
};
TEST(TypeAssertionTest, Demo)
{
FooType<bool> fooType;
fooType.Bar();
}
十二、总结
本篇将常用的断言都介绍了一遍,内容比较多,有些还是很有用的。要真的到写案例的时候,也行只是一两种是最常用的,现在时知道有这么多种选择,以后才方便查询。