一、初始Gtest和框架搭建
1.4 Demo
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);
}
#include <gtest/gtest.h>
TEST(FooTest, HandleNoneZeroInput)
{
EXPECT_EQ(2, Foo(4, 10));
EXPECT_EQ(6, Foo(30, 18));
}
二、断言
2.1 前言
GTest
中,断言的宏可以理解为分为两类,一类是ASSERT
系列,一类是EXPECT
系列。一个直观的解释就是:
ASSERT_*
系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前testcase)EXPECT_*
系列的断言,当检查点失败时,继续往下执行
2.2 自定义提示信息实例
未使用自定义提示
for (int i = 0; i < x.size(); ++i)
{
EXPECT_EQ(x[i], y[i]);
}
#结果:无法看出出错时到底是循环到哪里了
/*
g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(25): error: Value of: y[i]
Actual: 4
Expected: x[i]
Which is: 3
*/
使用<<操作符自定义提示输出
for (int i = 0; i < x.size(); ++i)
{
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
/*
g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(25): error: Value of: y[i]
Actual: 4
Expected: x[i]
Which is: 3
Vectors x and y differ at index 2
*/
2.3 bool值类型检查
ASSERT | EXPECT |
---|---|
检查失败退出函数 | 检查失败继续往下执行 |
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); |
2.4 数值型检查
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 |
2.5 字符串检查
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ(expected_str,actual_str); | EXPECT_STREQ(expected_str,actual_str); | 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); | same content, ignoring case |
ASSERT_STRCASENE(str1,str2); | EXPECT_STRCASENE(str1,str2); | different content, ignoring case |
2.6 显示返回成功或失败
- 直接返回成功
SUCCEED()
- 返回失败
Fatal assertion | Nonfatal assertion |
---|---|
FAIL(); | ADD_FAILURE(); |
TEST(ExplicitTest, Demo)
{
ADD_FAILURE() << "Sorry"; // None Fatal Asserton,继续往下执行。
//FAIL() << "Sorry!"; // Fatal Assertion,不继续往下执行该案例。
SUCCEED();
}
2.7 异常检查
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 |
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*);
}
2.8 Predicate Assertions
是对ASSERT_TRUE
和EXPECT_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 |
bool MutuallyPrime(int m, int n)
{
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
*/
2.9 浮点型检查
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 |
2.9.1 相近数比较
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 |
2.10 Windows HRESULT 检查
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 |
CComPtr shell;
ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application"));
CComVariant empty;
ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty));
2.11 类型检查
template <typename T> class FooType
{
public:
void Bar()
{
testing::StaticAssertTypeEq<int, T>();
}
};
TEST(TypeAssertionTest, Demo)
{
FooType<bool> fooType;
fooType.Bar();
}
三、事件机制
3.1 前言
事件:在案例执行之前或之后做的一些操作。
共有三个粒度:
- 全局级别的。在所有案例的第一个执行前,和所有案例最后一个执行后。
- TestSuite级别的。在某一批案例中的第一个案例前,最后一个案例执行后。
- TsetCase级别的。每个TestCase前后。
特别需要注意区分粒度。
粒度 | 解释 | |
---|---|---|
全局 | 有50个testcase,SetUp 在第1个testcase前执行,TearDown 在第50个testcase后执行。 | |
TestSuite | 有50个testcase ,其中针对这一个TestSuite 的testcase 是第20-30个,则此SetUpTestCase 在第20个testcase前执行,TearDownTestCase 在第30个testcase 后执行。 | |
TestCase | SetUp使用此事件的每一个testcase前执行一次,TearDown在 使用此事件的每一个testcase后执行一次 |
3.2 全局级别
要实现全局级别的事件:
- 写一个类,继承
testing::Environment
类,实现SetUp
和TearDown
- 在main函数中通过
testing::AddGlobalTestEnvironment
把事件挂进来。
我们有50个testcase,SetUp
在第1个testcase前执行,TearDown
在第50个testcase后执行。
3.2.1 实现SetUP和TearDown
class FooEnvironment : public testing::Environment
{
public:
virtual void SetUp()
{
std::cout << "Foo FooEnvironment SetUP" << std::endl;
}
virtual void TearDown()
{
std::cout << "Foo FooEnvironment TearDown" << std::endl;
}
public:
int dwRet;
};
3.2.2 挂载事件
int _tmain(int argc, _TCHAR* argv[])
{
testing::AddGlobalTestEnvironment(new FooEnvironment);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
3.3 TestSuite事件
要实现TestSuite级别(某一批)的事件:
- 写一个类,继承
testing::Test
类,实现静态方法SetUpTestCase
和TearDownTestCase
我们有50个testcase
,其中针对这一个TestSuite
的testcase
是第20-30个,则此SetUpTestCase
在第20个testcase前执行,TearDownTestCase
在第30个testcase
后执行。
class FooTest : public testing::Test
{
protected:
static void SetUpTestCase()
{
shared_resource_ = new ;
}
static void TearDownTestCase()
{
delete shared_resource_;
shared_resource_ = NULL;
}
static T* shared_resource_;
};
在编写测试案例时,我们需要使用TEST_F
这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuite
TEST_F(FooTest, Given_When_Then)
{
// you can refer to shared_resource here
}
TEST_F(FooTest, Given_When_Then)
{
// you can refer to shared_resource here
}
3.4 TestCase事件
TestCase
是在每个testcase
执行前执行,也在每个testcase
执行后执行。
class TEST_Command_Parse : public testing::Test
{
public:
CoreInfo *coreInfo; 2. 在main函数中通过t`esting::AddGlobalTestEnvironment`把事件挂进来。
public:
virtual void SetUp()
{
coreInfo = InitCoreNetwork();
}
virtual void TearDown()
{
CloseCoreNetwork(coreInfo);
}
};
#include "gtest/gtest.h"
GTEST_API_ int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
四、死亡测试
//暂缺
五、运行参数
5.1 命令行参数
gtest同样能够处理命令行参数,因为在main函数中我们把命令行参数交给了gtest。
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
由gtest来搞定命令行问题,这样就可以使用命令行参数来使得gtest达到我们想要的效果,比如:
参数 | 作用 |
---|---|
–gtest_list_tests | 使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。 |
5.2 代码中指定FLAG
gtest
提供了不止一种设置运行参数的方法:
- 命令行参数
- 代码中指定FLAG
- 系统环境变量
- 优先级为:
命令行参数 > 代码中指定FLAG > 系统环境变量
- 代码指定FLAG:
testing::GTEST_FLAG(output) = "xml:"
代码中指定FLAG,可以使用testing::GTEST_FLAG
这个宏来设置,推荐将这句放在InitGoogleTest
之前,这样就可以使得对于同样的参数,命令行参数优先级高于代码指定。
int _tmain(int argc, _TCHAR* argv[])
{
testing::GTEST_FLAG(output) = "xml:";
testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();
}
5.3 列表
命令行参数 | 说明 |
---|---|
–gtest_list_tests | |
–gtest_filter | |
–gtest_also_run_disabled_tests | |
–gtest_repeat=[COUNT] | |
–gtest_color=(yes\no\auto) | |
–gtest_print_time | |
–gtest_output=xml[:DIRECTORY_PATH|:FILE_PATH] | |
异常处理 | 异常处理 |
–gtest_break_on_failure | 调试模式下,当案例失败时停止,方便调试 |
–gtest_throw_on_failure | |
–gtest_catch_exceptions |
5.4 总结
本篇主要介绍了gtest案例执行时提供的一些参数的使用方法,这些参数都非常有用。在实际编写gtest测试案例时肯定会需要用到的时候。至少我现在比较常用的就是:
- –gtest_filter
- –gtest_output=xml[:DIRECTORY_PATH|:FILE_PATH]
- –gtest_catch_exceptions
最后再总结一下我使用过程中遇到的几个问题: - 同时使用–gtest_filter和–gtest_output=xml:时,在xml测试报告中能否只包含过滤后的测试案例的信息。
- 有时,我在代码中设置 testing::GTEST_FLAG(catch_exceptions) = 1和我在命令行中使用–gtest_catch_exceptions结果稍有不同,在代码中设置FLAG方式有时候捕捉不了某些异常,但是通过命令行参数的方式一般都不会有问题。这是我曾经遇到过的一个问题,最后我的处理办法是既在代码中设置FLAG,又在命令行参数中传入–gtest_catch_exceptions。不知道是gtest在catch_exceptions方面不够稳定,还是我自己测试案例的问题。