博客首页
注册
建议与交流
排行榜
加入友情链接
推荐
投诉
搜索:
帮助
Moon
问渠那得清如许?为有源头活水来.
purelight.cublog.cn
管理博客
发表文章
留言
收藏夹
博客圈
音乐
相册
文章
首页
关于作者
姓名: 职业:IT 年龄: 位置:苏州 个性介绍:
||
<<
>>
||
我的分类
最新文章
·
常见的网上邻居访问问题精解
·
linux远程控制方法概述
·
vi图解
·
wget命令详解
·
wget 使用指南
最新留言
·
最最
冰雹
最新评论
·
怎么写?
·
《观书有感》-朱熹
..
·
taimeijinleba
·
是通假字吗??
·
123
最新收藏
统计信息
·
总访问量:33006
·
文章个数:142
·
评论条数:30
·
留言条数:1
·
网友推荐:
【置顶】致访问本blog的朋友
有这么一个版友,令我十分的伤感。<br>http://blog.chinaunix.net/u/10295/showart.php?id=287881<br><br>我创建本blog的目的,<span style="color: rgb(0, 128, 255);">主要是为本人所用</span>。搜集一些自认为对自己有用的东西,省得以后还要用google查找。<br><br>我是个较真的人,所以<span style="color: rgb(255, 1, 2);">以那个人的态度</span>来访问本blog的人,请以后<span style="color: rgb(255, 1, 2);">不要再访问</span>了,进来的人请<span style="color: rgb(255, 1, 2);">马上退出</span>。<br>当然我非常希望有人能……
查看全文
发表于:2007-04-29 ┆
阅读(226)
┆
评论(0)
常见的网上邻居访问问题精解
转载:<a href="http://www.hebei.com.cn/node2/node17/node1080/userobject1ai317577.html" target="_blank">常见的网上邻居访问问题精解</a><br><br>Windows网上邻居互访的基本条件:<br><br>1) 双方计算机打开,且设置了网络共享资源;<br>2) 双方的计算机添加了 "Microsoft 网络文件和打印共享" 服务;<br>3) 双方都正确设置了网内IP地址,且必须在一个网段中;<br>4) 双方的计算机中都关闭了防火墙,或者防火墙策略中没有阻止网上邻居访问的策略。<br><br>Windows 98/2000/XP/2003访问XP的用户验证问题<br><br>首先关于启用G……
查看全文
发表于:2008-08-17 ┆
阅读(31)
┆
评论(0)
linux远程控制方法概述
转载:<a href="http://blog.chinaunix.net/u/19638/showart.php?id=1114354" target="_blank">linux远程控制方法概述</a><br><br>方法:<br> 1.rlogin、rsh等r系列<span href="http://www.linuxdiyf.com/bbs/tag.php?name=%C3%FC%C1%EE" onclick="tagshow(event)" class="t_tag">命令</span>。因为有较大的安全隐患,所以现在基本上废弃不用。 所以这里也不作详细介绍<br> <br> 2.telnet。telnet在linux和<span href="http://www.linuxdiyf.com/bbs/tag.php?name=windows" onclick="tagshow(event)" class="t_tag">windows</span>下均……
查看全文
发表于:2008-08-08 ┆
阅读(59)
┆
评论(0)
vi图解
转载:<a href="http://blog.chinaunix.net/u2/60901/showart.php?id=1097502" target="_blank">vi图解</a><br><br><br><br><br><br><br><br><br><br><br>
查看全文
发表于:2008-08-08 ┆
阅读(88)
┆
评论(0)
wget命令详解
转载:<a href="http://www.jzcode.net/twjc/soft/02347.htm" target="_blank">wget命令详解</a><br><br> wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上。它有以下功能和特点: <br> (1)支持断点下传功能;这一点,也是网络蚂蚁和FlashGet当年最大的卖点,现在,Wget也可以使用此功能,那些网络不是太好的用户可以放心了; <br> (2)同时支持FTP和HTTP下载方式;尽管现在大部分软件可以使用HTTP方式下载,但是,有些时候,仍然需要使用FTP方式下载软件; <br>……
查看全文
发表于:2008-07-29 ┆
阅读(32)
┆
评论(0)
wget 使用指南
转载:<a href="http://www.math.ecnu.edu.cn/%7Ejypan/linux/command/wget.htm" target="_blank">wget 使用指南</a><br><br> <p>wget是一个从网络上自动下载文件的自由工具。它支持HTTP,HTTPS和FTP协议,可以使用HTTP代理. </p> <p>所谓的自动下载是指,wget可以在用户退出系统的之后在后台执行。这意味这你可以登录系统,启动一个wget下载任务,然后退出系统,wget将在后台执行直到任务完成,相对于其它大部分浏览器在下载大量数据时需要用户一直的参与,这省去了极大的麻烦。 </p> <p>wget可以跟踪HTML页面上的链接依次下载来创建……
查看全文
发表于:2008-07-29 ┆
阅读(25)
┆
评论(0)
wget 使用技巧
转载:<a href="http://linuxtoy.org/archives/wget-tips.html" target="_blank">wget 使用技巧</a><p><a href="http://www.gnu.org/software/wget/">wget</a> 是一个命令行的下载工具。对于我们这些 Linux 用户来说,几乎每天都在使用它。下面为大家介绍几个有用的 wget 小技巧,可以让你更加高效而灵活的使用 wget。<span id="more-1503"></span></p> <ol><li><code>$ wget -r -np -nd http://example.com/packages/</code> <p>这条命令可以下载 http://example.com 网站上 packages 目录中的所有文件。其中,<code>-np</code> 的作用……
查看全文
发表于:2008-07-29 ┆
阅读(20)
┆
评论(0)
Google C++ Testing Framework Primer
<div class="postbody clearfix"> <p><strong><span class="hilite1"><span class="hilite1">Google</span></span> C++ <span class="hilite2"><span class="hilite2">Test</span></span>ing Framework Primer</strong></p> <p> </p> <p>翻译:<a href="http://rayleex.spaces.live.com/blog/cns%21C32DFA3924AF2128%21218.entry" target="_blank">Ray Li </a><a href="http://rayleex.spaces.live.com/blog/cns%21C32DFA3924AF2128%21218.entry" target="_blank"></a>(<a href="mailto:ray.leex@gmail.com">ray.leex@gmail.com</a>) <br>修改日期:2008年7月6日<br>原文参见:<a href="http://code.google.com/p/googletest/wiki/GoogleTestPrimer" target="_blank">http://code.google.com/p/googletest/wiki/GoogleTestPrimer</a><a href="http://code.google.com/p/googletest/wiki/GoogleTestPrimer"></a> </p> <p> </p> <p><strong>Introduction</strong><strong>:为什么需要</strong><strong><span class="hilite1"><span class="hilite1">Google</span></span> C++ </strong><strong>测试框架?</strong> </p> <p> </p> <p><span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架帮助你更好地编写C++测试。 </p> <p> </p> <p>无论你是在Linux,Windows,还是Mac环境下工作,只要你编写C++代码,<span class="hilite1"><span class="hilite1">Google</span></span> 测试框架都可以帮上忙。 </p> <p> </p> <p>那么,哪些因素才能构成一个好的测试?以及,<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架怎样满足这些因素?我们相信: </p> <ol><li>测试应该是<em>独立</em>、<em>可重复</em>的。因为其他测试成功或失败而导致我们要对自己的测试进行debug是非常痛苦的。<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架通过将每个测试在不同的对象中运行,使得测试分离开来。当一个测试失败时,<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架允许你独立运行它以进行快速除错。 </li><li>测试应该能够被很好地<em>组织</em>,并反映被测代码的结构。<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架将测试组织成测试案例,案例中的测试可以共享数据和程序分支。这样一种通用模式能够很容易辨识,使得我们的测试容易维护。当开发人员在项目之间转换,开始在一个新的代码基上开始工作时,这种一致性格外有用。 </li><li>测试应该是<em>可移植</em>、<em>可重用</em>的。开源社区有很多平台独立的代码,它们的测试也应该是平台独立的。除开一些特殊情况,<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架运行在不同的操作系统上、与不同的编译器(gcc、icc、MSVC)搭配,<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架的测试很容易与不同的配置一起工作。 </li><li>当测试失败时,应该提供尽可能多的、关于问题的<em>信息</em>。<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架在第一个测试失败时不会停下来。相反,它只是将当前测试停止,然后继续接下来的测试。你也可以设置对一些非致命的错误进行报告,并接着进行当前的测试。这样,你就可以在一次“运行-编辑-编译”循环中检查到并修复多个bug。 </li><li>测试框架应该能将测试编写人员从一些环境维护的工作中解放出来,使他们能够集中精力于测试的<em>内容</em>。<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架自动记录下所有定义好的测试,不需要用户通过列举来指明哪些测试需要运行。 </li><li>测试应该<em>快速</em>。使用<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架,你可以重用多个测试的共享资源,一次性完成设置/解除设置,而不用使一个测试去依赖另一测试。</li></ol> <p>因为<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架基于著名的xUnit架构,如果你之前使用过JUnit或PyUnit的话,你将会感觉非常熟悉。如果你没有接触过这些测试框架,它也只会占用你大约10分钟的时间来学习基本概念和上手。所以,让我们开始吧! </p> <p> </p> <p>Note:本文偶尔会用“<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>”来代指“<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架”。 </p> <p> </p> <p><strong>基本概念</strong></p> <p> </p> <p>使用<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>时,你是从编写<em>断言</em>开始的,而断言是一些检查条件是否为真的语句。一个断言的结果可能是成功、非致命失败,或者致命失败。如果一个致命失败出现,他会结束当前的函数;否则,程序继续正常运行。 </p> <p> </p> <p><em>测试</em>使用断言来验证被测代码的行为。如果一个测试崩溃或是出现一个失败的断言,那么,该测试<em>失败</em>;否则该测试<em>成功</em>。 </p> <p> </p> <p>一个测试案例(<span class="hilite2"><span class="hilite2">test</span></span> case)包含了一个或多个测试。你应该将自己的测试分别归类到测试案例中,以反映被测代码的结构。当测试案例中的多个测试需要共享通用对象和子程序时,你可以把他们放到一个测试固件(<em><span class="hilite2"><span class="hilite2">test</span></span> fixture</em>)类中。 </p> <p> </p> <p>一个<em>测试程序</em>可以包含多个测试案例。 </p> <p> </p> <p>从编写单个的断言开始,到创建测试和测试案例,我们将会介绍怎样编写一个测试程序。 </p> <p> </p> <p><strong>断言</strong> </p> <p> </p> <p><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>中的断言是一些与函数调用相似的宏。要测试一个类或函数,我们需要对其行为做出断言。当一个断言失败时,<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>会在屏幕上输出该代码所在的源文件及其所在的位置行号,以及错误信息。也可以在编写断言时,提供一个自定义的错误信息,这个信息在失败时会被附加在<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>的错误信息之后。 </p> <p> </p> <p>断言常常成对出现,它们都测试同一个类或者函数,但对当前功能有着不同的效果。ASSERT_*版本的断言失败时会产生致命失败,并<strong>结束当前函数</strong>。EXPECT_*版本的断言产生非致命失败,而不会中止当前函数。通常更推荐使用EXPECT_*断言,因为它们运行一个测试中可以有不止一个的错误被报告出来。但如果在编写断言如果失败,就没有必要继续往下执行的测试时,你应该使用ASSERT_*断言。 </p> <p> </p> <p>因为失败的ASSERT_*断言会立刻从当前的函数返回,可能会跳过其后的一些的清洁代码,这样也许会导致空间泄漏。根据泄漏本身的特质,这种情况 也许值得修复,也可能不值得我们关心——所以,如果你得到断言错误的同时,还得到了一个堆检查的错误,记住上面我们所说的这一点。 </p> <p> </p> <p>要提供一个自定义的错误消息,只需要使用<<操作符,或一个<<操作符的序列,将其输入到框架定义的宏中。下面是一个例子: </p> <p> </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span>ASSERT_EQ(x.size(), y.size()) << </span><span class="string">"Vectors x and y are of unequal length"</span><span>; </span></span></li><li><span><span class="keyword">for</span><span> (</span><span class="datatypes">int</span><span> i = 0; i < x.size(); ++i) { </span></span></li><li><span> EXPECT_EQ(x[i], y[i]) << <span class="string">"Vectors x and y differ at index "</span><span> << i; </span></span></li><li><span>} </span></li></ol></div><pre style="display: none;" name="code" class="cpp">ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; }</pre> <p>任何能够被输出到ostream中的信息都可以被输出到一个断言宏中——特别是C字符串和string对象。如果一个宽字符串(wchar_t*, windows上UNICODE模式TCHAR*或std::wstring)被输出到一个断言中,在打印时它会被转换成UTF-8编码。 </p> <p> </p> <p><strong>基本断言</strong> </p> <p> </p> <p>下面这些断言实现了基本的true/false条件测试。 </p> <p> </p> <table border="1" cellpadding="0" cellspacing="0" width="500"> <tbody> <tr> <td valign="top" width="167"><strong>致命断言</strong></td> <td valign="top" width="166"><strong>非致命断言</strong></td> <td valign="top" width="165"><strong>验证条件</strong></td> </tr> <tr> <td valign="top" width="167">ASSERT_TRUE(<em>condition</em>);</td> <td valign="top" width="166">EXPECT_TRUE(<em>condition</em>); </td> <td valign="top" width="165"><em>condition</em>为真</td> </tr> <tr> <td valign="top" width="167">ASSERT_FALSE(<em>condition</em>); </td> <td valign="top" width="166">EXPECT_FALSE(<em>condition</em>); </td> <td valign="top" width="165"><em>condition</em> 为假</td> </tr> </tbody> </table> <p> </p> <p>记住,当它们失败时,ASSERT_*产生一个致命失败并从当前函数返回,而EXCEPT_*产生一个非致命失败,允许函数继续运行。在两种情况下,一个断言失败都意味着它所包含的测试失败。 </p> <p> </p> <p>有效平台:Linux、Windows、Mac。 </p> <p> </p> <p><strong>二进制比较</strong> </p> <p> </p> <p>本节描述了比较两个值的一些断言。 </p> <p> </p> <table border="1" cellpadding="2" cellspacing="0" width="500"> <tbody> <tr> <td valign="top" width="166"><strong>致命断言</strong></td> <td valign="top" width="166"><strong>非致命断言</strong></td> <td valign="top" width="166"><strong>验证条件</strong></td> </tr> <tr> <td valign="top" width="166">ASSERT_EQ(<em>expected</em>, <em>actual</em>);</td> <td valign="top" width="166">EXPECT_EQ(<em>expected</em>, <em>actual</em>);</td> <td valign="top" width="166"><em>expected</em> == <em>actual</em></td> </tr> <tr> <td valign="top" width="166">ASSERT_NE(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166">EXPECT_NE(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166"><em>val1</em> != <em>val2</em></td> </tr> <tr> <td valign="top" width="166">ASSERT_LT(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166">EXPECT_LT(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166"><em>val1</em> < <em>val2</em></td> </tr> <tr> <td valign="top" width="166">ASSERT_LE(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166">EXPECT_LE(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166"><em>val1</em> <= <em>val2</em></td> </tr> <tr> <td valign="top" width="166">ASSERT_GT(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166">EXPECT_GT(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166"><em>val1</em> > <em>val2</em></td> </tr> <tr> <td valign="top" width="166">ASSERT_GE(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166">EXPECT_GE(<em>val1</em>, <em>val2</em>);</td> <td valign="top" width="166"><em>val1</em> >= <em>val2</em></td> </tr> </tbody> </table> <p> </p> <p>在出现失败事件时,<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>会将两个值(<em>Val1</em>和<em>Val2</em>)都打印出来。在ASSERT_EQ*和EXCEPT_EQ*断言(以及我们随后介绍类似的断言)中,你应该把你希望测试的表达式放在<em>actual</em>(实际值)的位置上,将其期望值放在<em>expected</em>(期望值)的位置上,因为<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>的测试消息为这种惯例做了一些优化。 </p> <p> </p> <p>参数值必须是可通过断言的比较操作符进行比较的,否则你会得到一个编译错误。参数值还必须支持<<操作符来将值输入到ostream中。所有的C++内置类型都支持这一点。 </p> <p> </p> <p>这些断言可以用于用户自定义的型别,但你必须重载相应的比较操作符(如==、<等)。如果定义有相应的操作符,推荐使用ASSERT_*()宏,因为它们不仅会输出比较的结果,还会输出两个比较对象。 </p> <p> </p> <p>参数表达式总是只被解析一次。因此,参数表达式有一定的副作用(side effect,这里应该是指编译器不同,操作符解析顺序的不确定性)也是可以接受的。但是,同其他普通C/C++函数一样,参数表达式的解析顺序是不确定的(如,一种编译器可以自由选择一种顺序来进行解析),而你的代码不应该依赖于某种特定的参数解析顺序。 </p> <p> </p> <p>ASSERT_EQ()对指针进行的是指针比较。即,如果被用在两个C字符串上,它会比较它们是否指向同样的内存地址,而不是它们所指向的字符串是否有相同值。所以,如果你想对两个C字符串(例如,const char*)进行值比较,请使用ASSERT_STREQ()宏,该宏会在后面介绍到。特别需要一提的是,要验证一个C字符串是否为空(NULL),使用ASSERT_STREQ(NULL, c_string)。但是要比较两个string对象时,你应该使用ASSERT_EQ。 </p> <p> </p> <p>本节中介绍的宏都可以处理窄字符串对象和宽字符串对象(string和wstring)。 </p> <p> </p> <p>有效平台:Linux、Windows、Mac。 </p> <p> </p> <p><strong>字符串比较</strong></p> <p> </p> <p>该组断言用于比较两个C字符串。如果你想要比较两个string对象,相应地使用EXPECT_EQ、EXPECT_NE等断言。 </p> <p> </p> <table border="1" cellpadding="2" cellspacing="0" width="700"> <tbody> <tr> <td valign="top" width="235"><strong>致命断言</strong></td> <td valign="top" width="234"><strong>非致命断言</strong></td> <td valign="top" width="229"><strong>验证条件</strong></td> </tr> <tr> <td valign="top" width="235">ASSERT_STREQ(<em>expected_str</em>, <em>actual_str</em>);</td> <td valign="top" width="234">EXPECT_STREQ(<em>expected_str</em>, <em>actual_str</em>);</td> <td valign="top" width="229">两个C字符串有相同的内容</td> </tr> <tr> <td valign="top" width="235">ASSERT_STRNE(<em>str1</em>, <em>str2</em>);</td> <td valign="top" width="234">EXPECT_STRNE(<em>str1</em>, <em>str2</em>);</td> <td valign="top" width="229">两个C字符串有不同的内容</td> </tr> <tr> <td valign="top" width="235">ASSERT_STRCASEEQ(<em>expected_str</em>, <em>actual_str</em>);</td> <td valign="top" width="234">EXPECT_STRCASEEQ(<em>expected_str</em>, <em>actual_str</em>);</td> <td valign="top" width="229">两个C字符串有相同的内容,忽略大小写</td> </tr> <tr> <td valign="top" width="235">ASSERT_STRCASENE(<em>str1</em>, <em>str2</em>);</td> <td valign="top" width="234">EXPECT_STRCASENE(<em>str1</em>, <em>str2</em>);</td> <td valign="top" width="229">两个C字符串有不同的内容,忽略大小写</td> </tr> </tbody> </table> <p> </p> <p>注意断言名称中出现的“CASE”意味着大小写被忽略了。 </p> <p> </p> <p>*STREQ*和*STRNE*也接受宽字符串(wchar_t*)。如果两个宽字符串比较失败,它们的值会做为UTF-8窄字符串被输出。 </p> <p> </p> <p>一个NULL空指针和一个空字符串会被认为是<em>不一样</em>的。 </p> <p> </p> <p>有效平台:Linux、Windows、Mac。 </p> <p> </p> <p>参见:更多的字符串比较的技巧(如子字符串、前缀和正则表达式匹配),请参见[Advanced Guide Advanced <span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span> Guide]。 </p> <p> </p> <p><strong>简单的测试</strong> </p> <p> </p> <p>要创建一个测试: </p> <ol><li>使用<span class="hilite2"><span class="hilite2">TEST</span></span>()宏来定义和命名一个测试函数,它们是一些没有返回值的普通C++函数。 </li><li>在这个函数中,与你想要包含的其它任何有效C++代码一起,使用<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>提供的各种断言来进行检查。 </li><li>测试的结果由其中的断言决定;如果测试中的任意断言失败(无论是致命还是非致命),或者测试崩溃,那么整个测试就失败了。否则,测试通过。 </li></ol> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span><span class="hilite2"><span class="hilite2">TEST</span></span>(<span class="hilite2"><span class="hilite2">test</span></span>_case_name, <span class="hilite2"><span class="hilite2">test</span></span>_name) { </span></span></li><li><span>... <span class="hilite2"><span class="hilite2">test</span></span> body ... </span></li><li><span>} </span></li></ol></div><pre style="display: none;" name="code" class="cpp"><span class="hilite2"><span class="hilite2">TEST</span></span>(<span class="hilite2"><span class="hilite2">test</span></span>_case_name, <span class="hilite2"><span class="hilite2">test</span></span>_name) { ... <span class="hilite2"><span class="hilite2">test</span></span> body ... }</pre> <p><span class="hilite2"><span class="hilite2">TEST</span></span>()的参数是从概括到特殊的。<em>第一个</em>参数是测试案例的名称,<em>第二个</em>参数是测试案例中的测试的名称。记住,一个测试案例可以包含任意数量的独立测试。一个测试的<em>全称</em>包括了包含它的测试案例名称,及其独立的名称。不同测试案例中的独立测试可以有相同的名称。 </p> <p> </p> <p>举例来说,让我们看一个简单的整数函数: </p> <p> </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span class="datatypes">int</span><span> Factorial(</span><span class="datatypes">int</span><span> n); </span><span class="comment">// 返回n的阶乘</span><span> </span></span></li></ol></div><pre style="display: none;" name="code" class="cpp">int Factorial(int n); // 返回n的阶乘</pre> <p> </p> <p><span style="font-family: courier new,courier;">这个函数的测试案例应该看起来像是: </span></p> <p> </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span class="comment">// 测试0的阶乘</span><span> </span></span></li><li><span><span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>, HandlesZeroInput) { </span></li><li><span> EXPECT_EQ(1, Factorial(0)); </span></li><li><span>} </span></li><li><span><span class="comment">// 测试正数的阶乘</span><span> </span></span></li><li><span><span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>, HandlesPositiveInput) { </span></li><li><span> EXPECT_EQ(1, Factorial(1)); </span></li><li><span> EXPECT_EQ(2, Factorial(2)); </span></li><li><span> EXPECT_EQ(6, Factorial(3)); </span></li><li><span> EXPECT_EQ(40320, Factorial(8)); </span></li><li><span>} </span></li></ol></div><pre style="display: none;" name="code" class="cpp">// 测试0的阶乘 <span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>, HandlesZeroInput) { EXPECT_EQ(1, Factorial(0)); } // 测试正数的阶乘 <span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>, HandlesPositiveInput) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); }</pre> <p> </p> <p><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>根据测试案例来分组收集测试结果,因此,逻辑相关的测试应该在同一测试案例中;换句话说,它们的<span class="hilite2"><span class="hilite2">TEST</span></span>()的第一个参数应该是一样的。在上面的例子中,我们有两个测试,HandlesZeroInput和HandlesPostiveInput,它们都属于同一个测试案例Factorial<span class="hilite2"><span class="hilite2">Test</span></span>。 </p> <p> </p> <p>有效平台:Linux、Windows、Mac。 </p> <p> </p> <p><strong>测试固件(</strong><strong><span class="hilite2"><span class="hilite2">Test</span></span> Fixtures</strong><strong>,又做测试夹具、测试套件):在多个测试中使用同样的数据配置</strong> </p> <p> </p> <p>当你发现自己编写了两个或多个测试来操作同样的数据,你可以采用一个<em>测试固件</em>。它让你可以在多个不同的测试中重用同样的对象配置。 </p> <p> </p> <p>要创建测试固件,只需: </p> <ol><li>创建一个类继承自<span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span>。将其中的成员声明为protected:或是public:,因为我们想要从子类中存取固件成员。 </li><li>在该类中声明你计划使用的任何对象。 </li><li>如果需要,编写一个默认构造函数或者SetUp()函数来为每个测试准备对象。常见错误包括将SetUp()拼写为Setup()(小写了u)——不要让它发生在你身上。 </li><li>如果需要,编写一个析构函数或者TearDown()函数来释放你在SetUp()函数中申请的资源。要知道什么时候应该使用构造函数/析构函数,什么时候又应该使用SetUp()/TearDown()函数,阅读我们的FAQ。 </li><li>如果需要,定义你的测试所需要共享的子程序。</li></ol> <p>当我们要使用固件时,使用<span class="hilite2"><span class="hilite2">TEST</span></span>_F()替换掉<span class="hilite2"><span class="hilite2">TEST</span></span>(),它允许我们存取测试固件中的对象和子程序: </p> <p> </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(<span class="hilite2"><span class="hilite2">test</span></span>_case_name, <span class="hilite2"><span class="hilite2">test</span></span>_name) { </span></span></li><li><span>... <span class="hilite2"><span class="hilite2">test</span></span> body ... </span></li><li><span>} </span></li></ol></div><pre style="display: none;" name="code" class="cpp"><span class="hilite2"><span class="hilite2">TEST</span></span>_F(<span class="hilite2"><span class="hilite2">test</span></span>_case_name, <span class="hilite2"><span class="hilite2">test</span></span>_name) { ... <span class="hilite2"><span class="hilite2">test</span></span> body ... }</pre> <p> </p> <p>与<span class="hilite2"><span class="hilite2">TEST</span></span>()一样,第一个参数是测试案例的名称,但对<span class="hilite2"><span class="hilite2">TEST</span></span>_F()来说,这个名称必须与测试固件类的名称一些。你可能已经猜到了:_F正是指固件。 </p> <p> </p> <p>不幸地是,C++宏系统并不允许我们创建一个单独的宏来处理两种类型的测试。使用错误的宏会导致编译期的错误。 </p> <p> </p> <p>而且,你必须在<span class="hilite2"><span class="hilite2">TEST</span></span>_F()中使用它之前,定义好这个测试固件类。否则,你会得到编译器的报错:“virtual outside class declaration”。 </p> <p>对于<span class="hilite2"><span class="hilite2">TEST</span></span>_F()中定义的每个测试,<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>将会: </p> <ol><li>在运行时创建一个<em>全新</em>的测试固件 </li><li>马上通过SetUp()初始化它, </li><li>运行测试 </li><li>调用TearDown()来进行清理工作 </li><li>删除测试固件。注意,同一测试案例中,不同的测试拥有不同的测试固件。<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>在创建下一个测试固件前总是会对现有固件进行删除。<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>不会对多个测试重用一个测试固件。测试对测试固件的改动并不会影响到其他测试。</li></ol> <p>例如,让我们为一个名为Queue的FIFO队列类编写测试,该类的接口如下: </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span class="keyword">template</span><span> <</span><span class="keyword">typename</span><span> E> </span><span class="comment">// E为元素类型</span><span> </span></span></li><li><span><span class="keyword">class</span><span> Queue { </span></span></li><li><span><span class="keyword">public</span><span>: </span></span></li><li><span> Queue(); </span></li><li><span> <span class="keyword">void</span><span> Enqueue(</span><span class="keyword">const</span><span> E& element); </span></span></li><li><span> E* Dequeue(); <span class="comment">// 返回 NULL 如果队列为空.</span><span> </span></span></li><li><span> <span class="datatypes">size_t</span><span> size() </span><span class="keyword">const</span><span>; </span></span></li><li><span> ... </span></li><li><span>}; </span></li></ol></div><pre style="display: none;" name="code" class="cpp">template <typename E> // E为元素类型 class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // 返回 NULL 如果队列为空. size_t size() const; ... };</pre> <p> </p> <p>首先,定义一个固件类。习惯上,你应该把它的名字定义为Foo<span class="hilite2"><span class="hilite2">Test</span></span>,这里的Foo是被测试的类。 </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span class="keyword">class</span><span> Queue<span class="hilite2"><span class="hilite2">Test</span></span> : </span><span class="keyword">public</span><span> <span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span> { </span></span></li><li><span><span class="keyword">protected</span><span>: </span></span></li><li><span> <span class="keyword">virtual</span><span> </span><span class="keyword">void</span><span> SetUp() { </span></span></li><li><span> q1_.Enqueue(1); </span></li><li><span> q2_.Enqueue(2); </span></li><li><span> q2_.Enqueue(3); </span></li><li><span> } </span></li><li><span> <span class="comment">// virtual void TearDown() {}</span><span> </span></span></li><li><span> Queue<<span class="datatypes">int</span><span>> q0_; </span></span></li><li><span> Queue<<span class="datatypes">int</span><span>> q1_; </span></span></li><li><span> Queue<<span class="datatypes">int</span><span>> q2_; </span></span></li><li><span>}; </span></li></ol></div><pre style="display: none;" name="code" class="cpp">class Queue<span class="hilite2"><span class="hilite2">Test</span></span> : public <span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span> { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue<int> q0_; Queue<int> q1_; Queue<int> q2_; };</pre> <p>在这个案例中,我们不需要TearDown(),因为每个测试后除了析构函数外不需要进行其它的清理工作了。 </p> <p> </p> <p>接下来我们使用<span class="hilite2"><span class="hilite2">TEST</span></span>_F()和这个固件来编写测试。 </p> <p> </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>, IsEmptyInitially) { </span></span></li><li><span> EXPECT_EQ(0, q0_.size()); </span></li><li><span>} </span></li><li><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>, DequeueWorks) { </span></li><li><span> <span class="datatypes">int</span><span>* n = q0_.Dequeue(); </span></span></li><li><span> EXPECT_EQ(NULL, n); </span></li><li><span> </span></li><li><span> n = q1_.Dequeue(); </span></li><li><span> ASSERT_TRUE(n != NULL); </span></li><li><span> EXPECT_EQ(1, *n); </span></li><li><span> EXPECT_EQ(0, q1_.size()); </span></li><li><span> <span class="keyword">delete</span><span> n; </span></span></li><li><span> </span></li><li><span> n = q2_.Dequeue(); </span></li><li><span> ASSERT_TRUE(n != NULL); </span></li><li><span> EXPECT_EQ(2, *n); </span></li><li><span> EXPECT_EQ(1, q2_.size()); </span></li><li><span> <span class="keyword">delete</span><span> n; </span></span></li><li><span>} </span></li></ol></div><pre style="display: none;" name="code" class="cpp"><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } <span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; }</pre> <p>上面这段代码既使用了ASSERT_*断言,又使用了EXPECT_*断言。经验上讲,如果你想要断言失败后,测试能够继续进行以显示更多的错误 时,你应该使用EXPECT_*断言;使用ASSERT_*如果该断言失败后继续往下执行毫无意义。例如,Dequeue测试中的第二个断言是 ASSERT_TURE(n!= NULL),因为我们随后会n指针解引用,如果n指针为空的话,会导致一个段错误。 </p> <p> </p> <p>当这些测试开始时,会发生如下情况: </p> <ol><li><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>创建一个Queue<span class="hilite2"><span class="hilite2">Test</span></span>对象(我们把它叫做t1)。 </li><li>t1.SetUp()初始化t1。 </li><li>第一个测试(IsEmptyInitiallly)在t1上运行。 </li><li>测试完成后,t1.TearDown()进行一些清理工作。 </li><li>t1被析构。 </li><li>以上步骤在另一个Queue<span class="hilite2"><span class="hilite2">Test</span></span>对象上重复进行,这回会运行DequeueWorks测试。</li></ol> <p>有效平台:Linux、Windows、Mac。 </p> <p> </p> <p>注意:当一个测试对象被构造时,<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>会自动地保存所有的<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>变量标识,对象析构后进行恢复。 </p> <p> </p> <p><strong>调用测试</strong> </p> <p> </p> <p><span class="hilite2"><span class="hilite2">TEST</span></span>()和<span class="hilite2"><span class="hilite2">TEST</span></span>_F()向<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>隐式注册它们的测试。因此,与很多其他的C++测试框架不同,你不需要为了运行你定义的测试而将它们全部再列出来一次。 </p> <p> </p> <p>在定义好测试后,你可以通过RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()来运行它们,如果所有测试成功,该函数返回0,否则会返回1.注意RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()会运行你链接到的所有测试——它们可以来自不同的测试案例,甚至是来自不同的文件。 </p> <p> </p> <p>当被调用时,RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()宏会: </p> <ol><li>保存所有的<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>标志。 </li><li>为一个侧测试创建测试固件对象。 </li><li>调用SetUp()初始化它。 </li><li>在固件对象上运行测试。 </li><li>调用TearDown()清理固件。 </li><li>删除固件。 </li><li>恢复所有<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>标志的状态。 </li><li>重复上诉步骤,直到所有测试完成。</li></ol> <p>此外,如果第二步时,测试固件的构造函数产生一个致命错误,继续执行3至5部显然没有必要,所以它们会被跳过。与之相似,如果第3部产生致命错误,第4部也会被跳过。 </p> <p> </p> <p>重要:你不能忽略掉RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()的返回值,否则gcc会报一个编译错误。这样设计的理由是自动化测试服务会根据测试退出返回码来决定一个测试是否通过,而不是根据其stdout/stderr输出;因此你的main()函数必须返回RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()的值。 </p> <p> </p> <p>而且,你应该只调用RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()一次。多次调用该函数会与<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>的一些高阶特性(如线程安全死亡测试thread-safe death <span class="hilite2"><span class="hilite2">test</span></span>s)冲突,因而是不被支持的。 </p> <p> </p> <p>有效平台:Linux、Windows、Mac。 </p> <p> </p> <p><strong>编写</strong><strong>main()</strong><strong>函数</strong> </p> <p> </p> <p>你可以从下面这个样板开始: </p> <p> </p> <div class="dp-highlighter"><div class="bar"><div class="tools">Cpp代码 <a href="http://www.javaeye.com/topic/212024#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" title="复制代码"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码"></a></div></div><ol class="dp-cpp" start="1"><li><span><span class="preprocessor">#include "this/package/foo.h"</span><span> </span></span></li><li><span><span class="preprocessor">#include <g<span class="hilite2"><span class="hilite2">test</span></span>/g<span class="hilite2"><span class="hilite2">test</span></span>.h></span><span> </span></span></li><li><span><span class="keyword">namespace</span><span> { </span></span></li><li><span><span class="comment">// 测试Foo类的测试固件</span><span> </span></span></li><li><span><span class="keyword">class</span><span> Foo<span class="hilite2"><span class="hilite2">Test</span></span> : </span><span class="keyword">public</span><span> <span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span> { </span></span></li><li><span><span class="keyword">protected</span><span>: </span></span></li><li><span> <span class="comment">// You can remove any or all of the following functions if its body</span><span> </span></span></li><li><span> <span class="comment">// is empty.</span><span> </span></span></li><li><span> Foo<span class="hilite2"><span class="hilite2">Test</span></span>() { </span></li><li><span> <span class="comment">// You can do set-up work for each <span class="hilite2"><span class="hilite2">test</span></span> here.</span><span> </span></span></li><li><span> } </span></li><li><span> <span class="keyword">virtual</span><span> ~Foo<span class="hilite2"><span class="hilite2">Test</span></span>() { </span></span></li><li><span> <span class="comment">// You can do clean-up work that doesn't throw exceptions here.</span><span> </span></span></li><li><span> } </span></li><li><span> <span class="comment">// If the constructor and destructor are not enough for setting up</span><span> </span></span></li><li><span> <span class="comment">// and cleaning up each <span class="hilite2"><span class="hilite2">test</span></span>, you can define the following methods:</span><span> </span></span></li><li><span> <span class="keyword">virtual</span><span> </span><span class="keyword">void</span><span> SetUp() { </span></span></li><li><span> <span class="comment">// Code here will be called immediately after the constructor (right</span><span> </span></span></li><li><span> <span class="comment">// before each <span class="hilite2"><span class="hilite2">test</span></span>).</span><span> </span></span></li><li><span> } </span></li><li><span> <span class="keyword">virtual</span><span> </span><span class="keyword">void</span><span> TearDown() { </span></span></li><li><span> <span class="comment">// Code here will be called immediately after each <span class="hilite2"><span class="hilite2">test</span></span> (right</span><span> </span></span></li><li><span> <span class="comment">// before the destructor).</span><span> </span></span></li><li><span> } </span></li><li><span> <span class="comment">// Objects declared here can be used by all <span class="hilite2"><span class="hilite2">test</span></span>s in the <span class="hilite2"><span class="hilite2">test</span></span> case for Foo.</span><span> </span></span></li><li><span>}; </span></li><li><span> </span></li><li><span><span class="comment">// <span class="hilite2"><span class="hilite2">Test</span></span>s that the Foo::Bar() method does Abc.</span><span> </span></span></li><li><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>, MethodBarDoesAbc) { </span></li><li><span> <span class="keyword">const</span><span> string input_filepath = </span><span class="string">"this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myinputfile.dat"</span><span>; </span></span></li><li><span> <span class="keyword">const</span><span> string output_filepath = </span><span class="string">"this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myoutputfile.dat"</span><span>; </span></span></li><li><span> Foo f; </span></li><li><span> EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); </span></li><li><span>} </span></li><li><span> </span></li><li><span><span class="comment">// <span class="hilite2"><span class="hilite2">Test</span></span>s that Foo does Xyz.</span><span> </span></span></li><li><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>, DoesXyz) { </span></li><li><span> <span class="comment">// Exercises the Xyz feature of Foo.</span><span> </span></span></li><li><span>} </span></li><li><span>} <span class="comment">// namespace</span><span> </span></span></li><li><span> </span></li><li><span><span class="datatypes">int</span><span> main(</span><span class="datatypes">int</span><span> argc, </span><span class="datatypes">char</span><span> **argv) { </span></span></li><li><span> <span class="hilite2"><span class="hilite2">test</span></span>ing::Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>(&argc, argv); </span></li><li><span> <span class="keyword">return</span><span> RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S(); </span></span></li><li><span>} </span></li></ol></div><pre style="display: none;" name="code" class="cpp">#include "this/package/foo.h" #include <g<span class="hilite2"><span class="hilite2">test</span></span>/g<span class="hilite2"><span class="hilite2">test</span></span>.h> namespace { // 测试Foo类的测试固件 class Foo<span class="hilite2"><span class="hilite2">Test</span></span> : public <span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span> { protected: // You can remove any or all of the following functions if its body // is empty. Foo<span class="hilite2"><span class="hilite2">Test</span></span>() { // You can do set-up work for each <span class="hilite2"><span class="hilite2">test</span></span> here. } virtual ~Foo<span class="hilite2"><span class="hilite2">Test</span></span>() { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each <span class="hilite2"><span class="hilite2">test</span></span>, you can define the following methods: virtual void SetUp() { // Code here will be called immediately after the constructor (right // before each <span class="hilite2"><span class="hilite2">test</span></span>). } virtual void TearDown() { // Code here will be called immediately after each <span class="hilite2"><span class="hilite2">test</span></span> (right // before the destructor). } // Objects declared here can be used by all <span class="hilite2"><span class="hilite2">test</span></span>s in the <span class="hilite2"><span class="hilite2">test</span></span> case for Foo. }; // <span class="hilite2"><span class="hilite2">Test</span></span>s that the Foo::Bar() method does Abc. <span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>, MethodBarDoesAbc) { const string input_filepath = "this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myinputfile.dat"; const string output_filepath = "this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myoutputfile.dat"; Foo f; EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); } // <span class="hilite2"><span class="hilite2">Test</span></span>s that Foo does Xyz. <span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace int main(int argc, char **argv) { <span class="hilite2"><span class="hilite2">test</span></span>ing::Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>(&argc, argv); return RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S(); }</pre> <p> </p> <p><span class="hilite2"><span class="hilite2">test</span></span>ing::Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>()函数负责解析命令行传入的<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>标志,并删除所有它可以处理的标志。这使得用户可以通过各种不同的标志控制一个测试程序的行为。关于这一点我们会在G<span class="hilite2"><span class="hilite2">Test</span></span>Advanced中讲到。你必须在调用RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()之前调用该函数,否则就无法正确地初始化标示。 </p> <p> </p> <p>在Windows上Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>()可以支持宽字符串,所以它也可以被用在以UNICODE模式编译的程序中。 </p> <p> </p> <p><strong>进阶阅读</strong> </p> <p> </p> <p>恭喜你!你已经学到了一些<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>基础。你可以从编写和运行几个<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>测试开始,再阅读一下<a href="http://code.google.com/p/googletest/wiki/GoogleTestSamples" target="_blank">GoogleTestSamples</a><a href="http://code.google.com/p/googletest/wiki/GoogleTestSamples"></a>,或是继续研究<a href="http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide" target="_blank">GoogleTestAdvancedGuide</a>,其中描述了很多更有用的<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>特性。 </p> <p> </p> <p><strong>已知局限</strong> </p> <p> </p> <p><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>被设计为线程安全的。但是,我们还没有时间在各种平台上实现同步原语(synchronization primitives)。因此,目前从两个线程同时使用<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>断言是不安全的。由于通常断言是在主线程中完成的,因此在大多数测试中这都不算问题。如果你愿意帮忙,你可以试着在g<span class="hilite2"><span class="hilite2">test</span></span>-port.h中实现必要的同步原语。</p> </div>
查看全文
发表于:2008-07-25 ┆
阅读(46)
┆
评论(0)
痔疮的防冶有哪些方法
原文出处:<a href="http://www.39.net/disease/zc/yf/183494.html" target="_blank">痔疮的防冶有哪些方法</a><br><br><p><font face="Verdana"> 痔多数处于静止、无症状状态,只有并发出血、血栓形成、痔块脱出以及痔嵌顿等,才需积极处理。</font></p> <p><font face="Verdana"> (一)日常生活防治</font></p> <p><font face="Verdana"> 1.养成良好的生活习惯,少吃辛辣食品。</font></p> <p><font face="Verdana"> 2.日常生活中要注意变换体位。</font></p> <p><font face="Verdana"> 3.保持大便通畅,多食含纤维……
查看全文
发表于:2008-07-23 ┆
阅读(57)
┆
评论(0)
痔疮的预防
原文出处:<a href="http://ask.39.net/question/3001064.html" target="_blank">痔疮的预防</a><br><br><span id="sContent">痔疮的发病率很高,痔疮患者经手术治疗或其它疗法治疗后,复发率亦较高。究其原因,除治疗不彻底外,不注意预防痔疮的发生,也是重要的因素,预防痔疮的发生,主要有以下几个方面:<br><br>(1) 加强锻炼:经常参加多种体育活动如广播体操、太极拳、气功、踢毽子等,能够增强机体的抗病能力,减少疾病发生的可能,对于痔疮也有一定的预防作用。这是因 为体育锻炼有益于血液循环,可以调和人体气血,促进胃肠蠕动……
查看全文
发表于:2008-07-23 ┆
阅读(19)
┆
评论(0)
令人郁闷的时区代码
转载:<a href="http://www.litrin.net/?q=node/130" target="_blank">令人郁闷的时区代码</a><span align="center"><p>研究PHP生成RSS2.0文件时,我发现利用阅读工具浏览时总是有时间不对的问题CST这个时区究竟 代表了什么?在一台 Linux 系统里运行 date 命令可以得到这种格式的时间: "Wed Dec 7 14:15:22 CST 2005". 搜索 CST, 可以发现它竟同时代表了四个时区:</p> <pre>CST Central Standard Time (USA) UT-6:00 //美国中部时间<br>CST Central Standard Time (Australia) UT+9:30 //澳大利亚时间<br>CST China Standard……
查看全文
发表于:2008-07-18 ┆
阅读(72)
┆
评论(0)
svn在linux下的使用(svn命令)
整理资料: <a href="http://hi.baidu.com/panzhiqi/blog/item/178d0fcaa47d2582c8176828.html" target="_blank">svn在linux下的使用(svn命令)</a><br> <span style="text-decoration: underline;"></span><a href="http://blog.csdn.net/shiqiang1234/archive/2007/05/30/1630946.aspx" target="_blank">svn 命令集合--学习总结</a><br><br><p><strong>1、</strong>将文件checkout到本地目录</p> <div style="border: 1px solid rgb(204, 204, 2……
查看全文
发表于:2008-06-20 ┆
阅读(98)
┆
评论(0)
svn 命令简要HOWTO
原文出处:<a href="http://http//linux.bloghome.cn/posts/334.html" target="_blank">svn 命令简要HOWTO</a><br><br> 常用的svn命令的一个简要介绍,很有用的: <br> <strong><u>CREATE REPOSITORY</u></strong><br><br><table style="border: 1px solid rgb(153, 153, 153); width: 583px; font-size: 12px; height: 24px;" align="center"><tbody><tr><td>$ svnadmin create /usr/local/svn/newrepos</td></tr></tbody></table><br><p><strong><u>IMPORT MODULE <br></u></strong></p><table style="border: 1px solid rgb(15……
查看全文
发表于:2008-06-20 ┆
阅读(87)
┆
评论(0)
通过udev自动挂载U盘的方法
<div style="text-align: left;">原文出处:<a href="http://blog.chinaunix.net/u/25969/showart_529230.html" target="_blank">通过udev自动挂载U盘的方法</a><br></div><font style="font-size: 14pt;" color="#02368d"><b><br></b></font><div style="text-align: center;"><font style="font-size: 14pt;" color="#02368d"><b> 通过udev自动挂载U盘的方法</b></font><br></div><hr style="width: 100%; height: 2px;"><font style="font-size: 14pt;" color="#02368d"><b><br></b></font>目前一些主流桌面系统(如Gnome,KDE,Xfce)……
查看全文
发表于:2008-05-23 ┆
阅读(79)
┆
评论(0)
基础知识
<table border="0" width="100%"><tbody><tr><td class="tdBlackTitle" width="88%"><span><b>Gold - 金币</b></span><br>你的角色每升一级都可以多拿 10,000 枚金币。例如,一个 10 级的角色可以拿 100,000 枚金币。一个角色最多可以在 99 级时拿 990,000 枚金币。Diablo II 不像 Diablo I,金币并不占用你的装备栏或储藏箱。</td> <td align="center" width="12%"><img src="http://d2.9cctv.com/UpFiles/BeyondPic/2006-09/20069248984992177.gif" onclick="javascript:window.open(this.src);" style="cursor: pointer;" alt="点此在……
查看全文
发表于:2008-05-14 ┆
阅读(66)
┆
评论(0)
mount
老是忘记<br><br>fdisk -l<br>mount /dev/sda1 /mnt/usb<br>mount /dev/sda1 /mnt/usb -o iocharset=cp936<br>
查看全文
发表于:2008-03-31 ┆
阅读(98)
┆
评论(0)
linux下编程宏的运用( #和##运用)
<h3>转载:<a href="http://blog.chinaunix.net/u1/33226/showart_489402.html" target="_blank">原文出处</a></h3><br>没时间看,先保留下来。<br><br><div id="art" style="margin: 15px;"> <div> <div>//-----------------------------------------------------------</div> <div>//例1</div> <div> </div> <div>//#和##运用<br>#include<stdio.h><br>//#define aa bb<br>#define A aa</div> <div>//#把宏参数变为一个字符串,<br>//#define STR(s) #s &n……
查看全文
发表于:2008-03-07 ┆
阅读(100)
┆
评论(0)
c++入门学习笔记继承
<h3>转载:<a href="http://www.hur.cn/program/cc/cc15/200604/26962.html" target="_blank">原文出处</a></h3><br><h2>c++入门学习笔记继承</h2>1. 继承的概念及重要性<br> inheritance :是<a class="channel_keylink" href="http://www.hur.cn/program/">软件</a>重用的一种形式,将相关的类组织起来,并分亨其间的共通数据和操作行为。<br> 最具吸引力的特点:新类可以从现有的类库中继承。提倡建立与现有的类有许多共性的新类来实现<a class="channel_keylink" href="http://www.hur.cn/program/">软件</a>的重用<br> 能添加……
查看全文
发表于:2008-03-04 ┆
阅读(76)
┆
评论(0)
IP组播技术综述
<h3>转载:<a href="http://www.net130.com/CMS/Pub/cert1/cert_ccie1/cert_ccie_qt/2005_08_10_82387.htm" target="_blank">原文出处</a></h3><br><div class="prod-news-content-title">IP组播技术综述 <div class="hr-line"><hr></div> </div> <div class="prod-news-content-title-sub"><a href="http://www.net130.com/">www.net130.com</a> 日期:2005-8-10 浏览次数:<script src="http://www.net130.com/CMS/Click.asp?NewsID=0581009093881185"></script>28096<……
查看全文
发表于:2008-02-22 ┆
阅读(219)
┆
评论(0)
讨论 Setsockopt选项
<h2>转载:<a href="http://www.chinaunix.net/jh/23/64174.html" target="_blank">原文出处</a></h2><br><br> <table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><th class="f24"><font color="#05006c"><h1>[精华] 讨论 Setsockopt选项</h1></font></th></tr> <tr><td height=""><hr bgcolor="#d9d9d9" size="1"></td></tr> <tr><td align="center" height="20"> http://www.chinaunix.net 作者:<a href="http://bbs.chinaunix.net/viewpro.php?uid=29829" target="_blank">无双</a> ……
查看全文
发表于:2008-02-22 ┆
阅读(192)
┆
评论(0)