gtest的安装和使用

Linux x86环境下

一,gtest安装

下载gtest源码包:gtest-1.7.0.zip

解压后进入gtest-1.7.0目录

cmake CMakeLists.txt

make 后生成两个静态库:libgtest.a libgtest_main.a

sudo cp libgtest*.a  /usr/lib 

sudo cp –a include/gtest /usr/include

 

下面是进入到sample目录下编译用例

cd sample

g++ sample1.cc sample1_unittest.cc -lgtest -lgtest_main -lpthread -o test1

g++ sample1.cc sample3-inl.h sample5_unittest.cc -lgtest -lgtest_main -lpthread -o test5

由于sample1.cc和sample1_unittest.cc文件中没有编写main函数,这里需要链接libgtest_main.a库

 

二,gtest使用

http://www.cnblogs.com/coderzh/archive/2009/04/06/1430364.html

 

gtest 即 Google C++单元测试框架

单元测试一般由编码人员自己完成,它的目的是隔离程序部件,并证明这些单个部件满足预期的功能。

它提供了丰富的断言、致命和非致命失败判断,能进行值参数化测试、类型参数化测试、“死亡测试”

1,断言

ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)

EXPECT_* 系列的断言,当检查点失败时,继续往下执行。

 

<1>布尔类型检查

ASSERT_TRUE(condition)  ASSERT_FALSE(condition)

<2>数值类型检查

ASSERT_EQ(expected, actual);

ASSERT_NE(val1, val2);

ASSERT_LT(val1, val2);

ASSERT_LE(val1, val2);

ASSERT_GT(val1, val2);

ASSERT_GE(val1, val2);

<3>字符串检查

ASSERT_STREQ(expected_str, actual_str);

ASSERT_STRNE(str1, str2);

ASSERT_STRCASEEQ(expected_str, actual_str);

ASSERT_STRCASENE(str1, str2);

 

 

一个简单的测试案例,可以参考sample/sample1.cc 和sample1_unittest.cc

另外sample2 是对类的接口函数的测试。

首先是一个求最大公约数的函数

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));
}

每个案例(TEST或TEST_F)应该是相互独立,互不影响的。

TEST宏有两个参数,第一个是TestSuiteName,第二个是TestCaseName

然后在main中添加如下代码让我们的案例运行起来。

int _tmain(int argc, _TCHAR* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

也可以不写main函数,直接在编译的时候链接libgtest_main.a库

 

2,gtest提供了多种事件机制,非常方便我们在案例之前或之后做一些操作。总结一下gtest的事件一共有3种:

<1>全局的,所有案例执行前后。

<2>TestSuite级别的,在某一批案例中第一个案例前,最后一个案例执行后。

<3> TestCase级别的,每个TestCase前后。

 

这里主要介绍TestCase事件

TestCase事件是挂在每个案例执行前后的,不过需要实现的是SetUp方法和TearDown方法:

1. SetUp()方法在每个TestCase之前执行

2. TearDown()方法在每个TestCase之后执行

要写一个类,这个类继承 testing::Test类。

class FooCalcTest:public testing::Test
{
protected:
    virtual void SetUp()
    {
        m_foo.Init();
    }
    virtual void TearDown()
    {
        m_foo.Finalize();
    }

    FooCalc m_foo;
};

TEST_F(FooCalcTest, HandleNoneZeroInput)
{
    EXPECT_EQ(4, m_foo.Calc(12, 16));
}

TEST_F(FooCalcTest, HandleNoneZeroInput_Error)
{
    EXPECT_EQ(5, m_foo.Calc(12, 16));
}

写测试案例时,使用TEST_F则开始测试前调用SetUp,结束案例后调用TearDown。也可以在这个类中定义其他的测试函数,供TEST_F调用。TEST_F的第一个参数类的名字,第二个参数是测试案例名。

gtest源码中的sample3也用的是TestCase事件。这个例子中定义了一个Queue模板,在QueueTest类中定义了SetUp函数和一个用来测试Map的MapTester函数。

 

3,参数化测试(mytest2)

首先必须添加一个类,继承testing::TestWithParam<T>,其中T就是你需要参数化的参数类型,这里是int。

然后使用TEST_P定义参数化案例。在TEST_P宏里,使用GetParam()获取当前的参数的具体值。

最后 使用INSTANTIATE_TEST_CASE_P这宏来告诉gtest你要测试的参数范围

#include <gtest/gtest.h>

class IsPrimeParamTest : public::testing::TestWithParam<int>
{

};

// 不使用参数化测试,就需要像这样写五次
TEST(IsPrimeTest, HandleTrueReturn1)
{
    EXPECT_TRUE(IsPrime(3));
    EXPECT_TRUE(IsPrime(5));
    EXPECT_TRUE(IsPrime(11));
    EXPECT_TRUE(IsPrime(23));
    EXPECT_TRUE(IsPrime(17));
}

// 使用参数化测试,只需要:
TEST_P(IsPrimeParamTest, HandleTrueReturn2)
{
    int n =  GetParam();
    EXPECT_TRUE(IsPrime(n));
}

// 定义参数
INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));

 

INSTANTIATE_TEST_CASE_P宏的三个参数:

第一个参数是测试案例的前缀,可以任意取。

第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同,如:IsPrimeParamTest

第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:

Range(begin, end[, step])

范围在begin~end之间,步长为step,不包括end

Values(v1, v2, ..., vN)

v1,v2到vN的值

ValuesIn(container) and ValuesIn(begin, end)

从一个C类型的数组或是STL容器,或是迭代器中取值

Bool()

取false 和 true 两个值

Combine(g1, g2, ..., gN)

这个比较强悍,它将g1,g2,...gN进行排列组合,g1,g2,...gN本身是一个参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。

说明:这个功能只在提供了<tr1/tuple>头的系统中有效。gtest会自动去判断是否支持tr/tuple,如果你的系统确实支持,而gtest判断错误的话,你可以重新定义宏GTEST_HAS_TR1_TUPLE=1。

 

4,命令行参数

--gtest_output=xml:dir:\foo.xml

指定输出到dir\foo.xml,不指定则输出到当前目录。也可以由系统变量GTEST_OUTPUT指定

--gtest_list_tests

使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。

--gtest_filter

对执行的测试案例进行过滤,支持通配符

 

 

好的单元测试具备以下特点:

1,  独立:即该测试用例的测试结果不受其他测试的影响

2,  有效的组织架构,清晰的命名:各个测试用例针对不同的测试对象,而对单个测试对象而言,又可能有多个测试用例对应该对象的多个功能。好的习惯是把这些用例以层次结构的形式组织起来,并使用清晰的命名,使得我们通过阅读用例名称即可明了该用例的功能

3,  可移植、可复用

4,  当用例失败时,提供尽可能多的有效信息

 

posted @ 2015-12-14 22:05  suo_suo  阅读(11520)  评论(0编辑  收藏  举报