Google Test In Action

                                                                                                                Part 1

Google C++ Testing Framework 

Friday,August 19,2011

 (注:插入图片过程复杂,涉及图片的都Ignore.)

 

目录

1.      Introduction. 2

2.      Setting. 2

3.      Demo. 3

4.      Assertions. 4

5.      Parameterized. 9

6.      Global Set-Up and Tear-Down. 10

7.      Other. 11

8.      Google C++ Testing Framework Samples. 12

9.      UI 16

 

 

 

 

1.     Introduction

 

第一部分已省略,详情见googletest官方网站:

http://code.google.com/p/googletest/

2.     Setting

 

1) 首先登录googletest官方网站下载相关的项目:
http://code.google.com/p/googletest/downloads/detail?name=gtest-1.6.0.zip

 

2) 将下载的gtest-1.6.0.zip解压,将得到如下的结构:

 

点击进入gtest-1.6.0\ msvc,用Visual Studio打开gtest.sln,进行编译,将会得到相应的gtestd.lib/gtest.lib文件(gtestd.lib对应Debug模式,gtest.lib对应Release模式)。

 

3) 配置相应的Visual Studio环境,配置路径如下:

Property Pages /  Configuration Properties / VC++ Directories  / Include Directories

Property Pages /  Configuration Properties / VC++ Directories  / Library Directories

Property Pages /  C/C++ /Code Generation Runtime Library

Property Pages / Linker / Input /Additional Dependencies (Debug / Release 下的 * . lib)

 

注:刚开始我忘了设置相应的lib文件 ,则编译阶段可以通过,但在连接阶段会抛出如下错误:

 

 

3.     Demo

首先做一个简单的Demo,以了解大统的流程,使用Google Test 做C++ 单元测试只要简单的三步,如下:

1)  添加要测试相关的相应头文件,和gtest.h头文件以引入testing framework:

    #include "gtest/gtest.h"

2)  编写所要测试的方法

int Func(int a, int b)
{
        if (a <= 0 || b <= 0) 
                   throw "my god!";
        return a + b;
}

 

3)      使用TEST宏去定义一个Test Case,不再需要写类似jUnit的runTest,test****()之类的方法,

Test宏的用法如下:

         TEST(test_case_name, test_name) {
                 ... test body ...
         }
如: 

TEST(FuncTest, HandleNoneZeroInput)

{

         EXPECT_EQ(2, Func(1,1)); 

         EXPECT_EQ(6, Func(3,4));

}

         该Test Case用于测试EXPECT_EQ()的两个参数是否相等,在下节进行具体的讲解。

4)       在main函数中调用InitGoogleTest(),RUN_ALL_TESTS(),以运行所有的TEST.

int _tmain(int argc, _TCHAR* argv[])

       std::cout<< "Running main() from glibtest.cpp ....\n";

 

       testing::InitGoogleTest(&argc, argv);

        

       return RUN_ALL_TESTS();

}

5)      运行Test ,如下图所示:

 

如果出现的都是[OK],则表示测试通过,否则将出现红色标志的[FAILED]表示该测试失败。
一个简单的Demo就结束了, 应该对Google Test有了一个大致的了解。
 

4.     Assertions

 

Google Test 提供了两种断言机制,分别是ASSERT_*EXPECT_*,我们可以把这两种的区别用C++里面的两个关键字来解释:continue,break;
ASSERT_* : “break”,    当检查点失败时,退出当前函数。
EXPECT_* : “continue”, 当检查点失败时,还会往下执行。
 
·         两个数值之间的比较

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

 
例如,对于[ASSERT| EXPECT]_EQ这个检查点用来检验第一个参数和第二个参数是否相等,第一个参数是你期望的值(expected,第二个参数是实际计算出来的值(actual)。
Ø 如果检查点是:EXPECT_EQ(2, Func(1,1)); 则相应的测试结果为:
 
表示期望值和实际值相等。[Func(int,int)在上面已经定义]
Ø 如果检查点是:EXPECT_EQ(6, Func(3,4)); 则相应的测试结果为:
 

         表示期望值和实际值不等。

Ø 如果用于测试vector和array里面的各个元素,则如下所示(可以将vector理解为array的现代版,所以在此只对vector做一个Demo):

// create a vector vec1 with 3 elements of value 1

vector <int> vec1 (3, 1);

// copy contructor : copy from vec1

vector <int> vec2 (vec1);

// create a vector vec3 with 3 elements of value 2

vector <int> vec3 (3, 2);

 

 

TEST(EqTest,HandleNoneZeroInput)

{

         for(vector<int>::size_type i = 0; i < vec1.size(); ++i)

         {

                 EXPECT_EQ(vec1[i],vec2[i]);       

                 EXPECT_EQ(vec1[i],vec3[i]);                                 

         }

}

 

测试结果如下:

 

 

如图所示,没有指出vector里面的相应元素值,如果要显示具体的数值,则可以重载<<来输出具体的数值:

ostream& operator<< (ostream& os,const string& str)

  return os << str;

}

      EXPECT_EQ(vec1[i],vec3[i]) << "Vectors x and y differ at index " << i;

     

如图所示,现在可以正确输出vector里面具体的数值。

·         字符串之间的比较 

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

            仍以简单的[ASSERT| EXPECT]_ STREQ和[ASSERT| EXPECT]_ STRNE这个检查点进行介绍:

char             *pChar  = "Company";

wchar_t          *pWChar = L"Company";

std::string      str     = "Company";

std::wstring     wstr    = L"Company";

 

TEST(StringCmpareTest,Demo)

{

         // *_STREQ : Verify the two C Strings have the same content

         EXPECT_STREQ("Company",pChar);

         EXPECT_STREQ(L"Company",pWChar);

 

         // *_STRNE : Verify the two C strings have different content 

         EXPECT_STRNE("Company_",pChar);

         EXPECT_STRNE(L"Company_",pWChar);

 

         EXPECT_STREQ("Company",str.c_str());  //c_str : c-style <-> C++

         EXPECT_STREQ(L"Company",wstr.c_str());

}

运行结果如下:                  

·         异常断言 

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


 直接上例子,如下:

TEST(FuncTest,HandleZeroInput)

{

  EXPECT_ANY_THROW(Func(10,0));

  EXPECT_THROW(Func(0,5),char*); 

}

 

第一个检查点期望语句抛出了一个任意的异常,第二个检查点期望语句抛出一个指定类型的异常。结果如下:

 

 

 

如果我们改一下上面的TEST,改成:

 

TEST(FuncTest,HandleZeroInput)

{

  EXPECT_ANY_THROW(Func(10,3));

  EXPECT_THROW(Func(1,5),int*); 

}

 

两个检查点都没有按预期的抛出异常,则出现如下结果:

 

 

 

 

 

 

 

·         Windows HRESULT 断言

对于Windows HRESULT 断言的Demo提供在ATL_COM项目中,由于对COM了解不够深入,在此只是简单的进行了演示(代码来自于gtest_unittest.cc第3914行开始,为了演示进行了简化):

static HRESULT UnexpectedHRESULTFailure() {

  return E_UNEXPECTED;

}

 

static HRESULT OkHRESULTSuccess() {

  return S_OK;

}

 

static HRESULT FalseHRESULTSuccess() {

  return S_FALSE;

}

 

TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED) {

  EXPECT_HRESULT_SUCCEEDED(S_OK);

  EXPECT_HRESULT_SUCCEEDED(S_FALSE);

}

 

TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED) {

  ASSERT_HRESULT_SUCCEEDED(S_OK);

  ASSERT_HRESULT_SUCCEEDED(S_FALSE);

}

 

TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED) {

  EXPECT_HRESULT_FAILED(E_UNEXPECTED);

}

 

TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED) {

  ASSERT_HRESULT_FAILED(E_UNEXPECTED);

}

测试结果如下:
 

在google的源码中,{ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)的定义是这样的:

#if GTEST_OS_WINDOWS

 

// Macros that test for HRESULT failure and success, these are only useful

// on Windows, and rely on Windows SDK macros and APIs to compile.

//

//    * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)

//

// When expr unexpectedly fails or succeeds, Google Test prints the

// expected result and the actual result with both a human-readable

// string representation of the error, if available, as well as the

// hex result code.

# define EXPECT_HRESULT_SUCCEEDED(expr) \

    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))

 

# define ASSERT_HRESULT_SUCCEEDED(expr) \

    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))

 

# define EXPECT_HRESULT_FAILED(expr) \

    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))

 

# define ASSERT_HRESULT_FAILED(expr) \

    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))

 

#endif  // GTEST_OS_WINDOWS

如何在实际项目中测试COM,可能还要继续深入了解一下。
COM在这里用于与.NET进行互操作,通过COM Interop(类型库导入工具tlbimp.exe,将COM中的*.idl或者*.exe导入到.NET DLL元数据)生成了互操作程序集(dll),可以将对COM的测试,转到用Nunit进行测试,由于本文档主要是针对Google Test的,关于如何在.NET中测试COM生成的互操作程序集,不在此进行说明 ,具体测试方法我已经在ATL_COM项目上进行了说明,在此只给出成功和失败的界面:
 
 
 

5.     Parameterized

First,有两个问题:
     a. 为什么要参数化?
     b. 如何参数?

 

第一个问题,我们为什么要进行参数化测试,如果我们写了一个函数(根据不同的参数返回不同的值),我们要测试该函数是否正确,我们可能要使用不同的参数 ,以gtest sample文件夹中的sample1.cc里面的 bool IsPrime(int n)为例,我们可能要使用多种参数对其进行测试。当然我们可以写多次EXPECT_*,但基本上只是参数上的不同,参数化测试可以进行相应的简化工作。

 

第二个问题,我们如何要进行参数化测试,其实很简单,分为如下几步:

        a).First,你要定义一个类,必须让该类继承::testing::WithParamInterface<T>,其中T就是你要进行参数化的类型:

// call GetParam() from TestWithParam<T> to get the test parameter.

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

{

  // You can implement all the usual class fixture members here.

};

       b). Then,使用TEST_P宏去定义Test Case (与上面的TEST宏不同,这里是TEST_P,其中P是parameterized/ pattern的意思),在这个TEST_P里面,我们可以使用TestWithParam<T>类中的GetParam()方法去取得相应的测试参数(那么测试参数从哪获取呢,不急,看第三步):

TEST_P(IsPrimeParamTest, HandleTrueReturn)

{

  // Inside a test, access the test parameter with the Getparam() method

  // of the TestWithParam<T> class:

  int n =  GetParam();

  // Virify : condition is true 

  EXPECT_TRUE(IsPrime(n));

}

        c).Finally,使用INSTANTIATE_TEST_CASE_P实例化(Instantiate)一个测试案例:

 

//Instantiate test case 

INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));

本例中其中第三个参数,使用了testing命名空间中的Values。

 

在testing命名空间中多种函数去生成相应的测试参数,我们可以使用以下任一函数:

Range(begin, end[, step])

Yields values {begin, begin+step, begin+step+step, ...}. The values do not include end. step defaults to 1.

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

Yields values {v1, v2, ..., vN}.

ValuesIn(container) and ValuesIn(begin, end)

Yields values from a C-style array, an STL-style container, or an iterator range [begin, end). container, begin, and end can be expressions whose values are determined at run time.

Bool()

Yields sequence {false, true}.

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

Yields all combinations (the Cartesian product for the math savvy) of the values generated by the N generators. This is only available if your system provides the <tr1/tuple> header. If you are sure your system does, and Google Test disagrees, you can override it by defining GTEST_HAS_TR1_TUPLE=1. See comments in include/gtest/internal/gtest-port.h for more information.

该Demo生成测试结果如下:

 

6.     Global Set-Up and Tear-Down

 

SetUp和TearDown可以放在多处,可以将其放在Test  level,Test Case level,Test Program level,这里我们将其作为全局的,放在应用程序级别,在所有案例的执行前后。

首先看下所要继承的Environment 类

class Environment 

{

public:

         virtual ~Environment() {}

         // Override this to define how to set up the environment.

         virtual void SetUp() {}

         // Override this to define how to tear down the environment.

         virtual void TearDown() {}

};

我们要自己编写相应的子类:

class MyEnvironment : public testing::Environment

{

public:

  virtual void SetUp() 

  {

           cout << "Environment SetUp...,\n

           you can set samething how to set up the environment" <<  endl;

  }

  virtual void TearDown() 

  {

           cout << "Environment TearDown...,\n

           you can set samething how to tear down the environment" << endl;

  }

};

接着使用::testing::AddGlobalTestEnvironment()在main实例化我们的子类:

         testing::Environment* const my_env = 

                 testing::AddGlobalTestEnvironment(new MyEnvironment);则在所有的案例执行前和执行后会分别启动相应的SetUp,TearDown,如图所示:

 

 

 

7.     Other  

 

其它还有比较杂乱和高级的主题,如FLAGS_gtest_*之类的方法很多,在此只好列出Demo中用到的进行说明,完整的请查看Google文档:

  1. FLAGS_gtest_output

 

          testing::FLAGS_gtest_output="xml:";

则生成类似的XML:

 

)。

  1. FLAGS_gtest_death_test_style

 

  ::testing::FLAGS_gtest_death_test_style = "fast";

         ::testing::FLAGS_gtest_death_test_style = "threadsafe";


(用于死亡测试,死亡测试DeathTest的优先级比普通Test的要高,详情见Part2)

 

  1. FLAGS_gtest_also_run_disabled_tests

可以对禁用的断言进行测试 。设置如下:

 

 

 

其它如上面提到的死亡测试(DeathTest)、禁用断言(DISABLED_)、事件(Event Listeners)等 ,见附件上的Demo或者Part 2部分。

8.     Google C++ Testing Framework Samples

http://code.google.com/p/googletest/wiki/V1_6_Samples可以下载到Google提供的Samples,这 里贴出其中的Sample #1,进行分析:

Sample#1由以下几个部分组成:

 

sample1.cc有如下两个方法:

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.

int Factorial(int n) { ... }

 

// Returns true iff n is a prime number.

bool IsPrime(int n) { ...  }

sample1_unittest.cc中就是对这两个方法的测试,可以看出具体分为三步:

 

 

// Step 1. Include necessary header files such that the stuff your

// test logic needs is declared.

//

// Don't forget gtest.h, which declares the testing framework.

 

#include "stdafx.h" 

#include <limits.h>

#include "sample1.h"

#include "gtest/gtest.h"

 

// Step 2. Use the TEST macro to define your tests.

//

// TEST has two parameters: the test case name and the test name.

// After using the macro, you should define your test logic between a

// pair of braces.  You can use a bunch of macros to indicate the

// success or failure of a test.  EXPECT_TRUE and EXPECT_EQ are

// examples of such macros.  For a complete list, see gtest.h.

//

// <TechnicalDetails>

//

// In Google Test, tests are grouped into test cases.  This is how we

// keep test code organized.  You should put logically related tests

// into the same test case.

//

// The test case name and the test name should both be valid C++

// identifiers.  And you should not use underscore (_) in the names.

//

// Google Test guarantees that each test you define is run exactly

// once, but it makes no guarantee on the order the tests are

// executed.  Therefore, you should write your tests in such a way

// that their results don't depend on their order.

//

// </TechnicalDetails>

 

 

// Tests Factorial().

 

// Tests factorial of negative numbers.

TEST(FactorialTest, Negative) {

  // This test is named "Negative", and belongs to the "FactorialTest"

  // test case.

  EXPECT_EQ(1, Factorial(-5));

  EXPECT_EQ(1, Factorial(-1));

  EXPECT_TRUE(Factorial(-10) > 0);

 

  // <TechnicalDetails>

  //

  // EXPECT_EQ(expected, actual) is the same as

  //

  //   EXPECT_TRUE((expected) == (actual))

  //

  // except that it will print both the expected value and the actual

  // value when the assertion fails.  This is very helpful for

  // debugging.  Therefore in this case EXPECT_EQ is preferred.

  //

  // On the other hand, EXPECT_TRUE accepts any Boolean expression,

  // and is thus more general.

  //

  // </TechnicalDetails>

}

 

// Tests factorial of 0.

TEST(FactorialTest, Zero) {

  EXPECT_EQ(1, Factorial(0));

}

 

// Tests factorial of positive numbers.

TEST(FactorialTest, Positive) {

  EXPECT_EQ(1, Factorial(1));

  EXPECT_EQ(2, Factorial(2));

  EXPECT_EQ(6, Factorial(3));

  EXPECT_EQ(40320, Factorial(8));

}

 

 

// Tests IsPrime()

 

// Tests negative input.

TEST(IsPrimeTest, Negative) {

  // This test belongs to the IsPrimeTest test case.

 

  EXPECT_FALSE(IsPrime(-1));

  EXPECT_FALSE(IsPrime(-2));

  EXPECT_FALSE(IsPrime(INT_MIN));

}

 

// Tests some trivial cases.

TEST(IsPrimeTest, Trivial) {

  EXPECT_FALSE(IsPrime(0));

  EXPECT_FALSE(IsPrime(1));

  EXPECT_TRUE(IsPrime(2));

  EXPECT_TRUE(IsPrime(3));

}

 

// Tests positive input.

TEST(IsPrimeTest, Positive) {

  EXPECT_FALSE(IsPrime(4));

  EXPECT_TRUE(IsPrime(5));

  EXPECT_FALSE(IsPrime(6));

  EXPECT_TRUE(IsPrime(23));

}

 

// Step 3. Call RUN_ALL_TESTS() in main().

//

// We do this by linking in src/gtest_main.cc file, which consists of

// a main() function which calls RUN_ALL_TESTS() for us.

//

// This runs all the tests you've defined, prints the result, and

// returns 0 if successful, or 1 otherwise.

//

// Did you notice that we didn't register the tests?  The

// RUN_ALL_TESTS() macro magically knows about all the tests we

// defined.  Isn't this convenient?

 

另外对于第三步Google提供的Samples都是直接调用

return RUN_ALL_TESTS();

 

对于要启动新的实例,最终的结果都是一闪而过,如果不是关心其具体的返回值,可以改成如下形式:

           cin.get();  

           return 0;

这样就可以了。

 

最后的测试全部通过:

 

9.     UI

另外类似于Nunit所提供的两个测试方式 (nunit-console.exe 、 nunit-gui.exe),Google Test也提供了一个UI的工具,经过分析源码,知道所有的代码测试最终会生成 一个.exe,如附件上的Demo,在Debug下面的glibtest.exe:

 

可以从命令行进行测试 ,且可以带入相应的运行参数(通过main的  int argc,   _TCHAR* argv[] 带入到testing::InitGoogleTest(&argc, argv);),UI(gtest-gbar)就是使用这个来进行测试的(这个UI同Nunit UI一样,也是用C# /Windows Form开发的,个人感觉,或许它们新的版本都会升级使用C#/WPF进行UI开发)。它的UI如下:

 

 

它的C#代码中,最关键的就是用了一个继承自Component 的 System.Diagnostics.Process类,这个类可以启动相应的进程(如打开IE等):

 

 

这么强大的工具在哪可以下呢?请点击:http://code.google.com/p/gtest-gbar/

 

 The Wall!


posted @ 2011-12-29 16:43 Libra.Thinker 阅读(1040) 评论(0) 编辑

最近搬家,书太多,搞出了满满二大包带一箱书,主要有JavaScript,jQuery,ExtJS,C#,LINQ,AJAX,Silverlight,.NET,SQLServer,C++,JAVA等,因为搬家麻烦,想先卖出几本,有要的朋友到淘宝上购买:

http://item.taobao.com/auction/item_detail.htm?item_num_id=8342968882  -- ASP.NET AJAX实战

http://item.taobao.com/auction/item_detail.htm?item_num_id=8343084652  -- C#本质论(第3版)

http://item.taobao.com/auction/item_detail.htm?item_num_id=8342860582  -- ASP.NET电子商务开发实战

http://item.taobao.com/auction/item_detail.htm?item_num_id=8342729634  -- Microsoft SQL Server2005技术内幕:T-SQL程序设计

http://item.taobao.com/auction/item_detail.htm?item_num_id=8342553090  -- Silverlight 揭秘

 

如果这些都卖了的话,我再放几个卖卖,例外价格可商量!

===the wall===

posted @ 2010-11-12 21:58 Libra.Thinker 阅读(40) 评论(0) 编辑

目前除了使用Eclipse进行Andriod的开发外,Moto公司还进行了扩展使得可以更好地Moto手机的开发,该工具有如下特点:

   完整开发包   面向摩托罗拉手机   代码段   应用程序创建向导   数据库管理   手机模拟器    配置包    使用 C 开发 

具体详情如下图如示(如下图片摘自Moto公司)

  

  

 下载地址: http://developer.motorola.com/docstools/motodevstudio/download/

提供两种模式:

  • FullInstaller: Includes Eclipse environment


  

  • EclipsePlug-in Version: Requires an existing Eclipse environment

 

一些相应的信息,诸如2.0 版本中的新增功能,已知问题等可查看

http://developer.motorola.com/docstools/library/MOTODEV_Studio_for_Android_Release_Notes/

 

欢迎界面如下:


 

好了,就说这么多!

posted @ 2010-10-30 23:45 Libra.Thinker 阅读(148) 评论(1) 编辑

,

本来准备在amazon上买一本,但加上空运等费用大约200-300人民币,已经下订单的我,想了想第二天取消了该订单,自己请别人打印了一本,还不错,

看英文的比中文的爽多了。

这本书非常不错。可惜3.0的翻译太差,如果有想法,可以一起咱们重新翻译一下。

这本书不错,看完这本书,对C#的理解会有一定的提高 ,要知道Scott Guthrie也看这本书!

话不多说,多说无益!

posted @ 2010-10-24 20:43 Libra.Thinker 阅读(267) 评论(10) 编辑