白盒测试

发布新日志

  • QTP的一些小知识【转载】

    2008-10-13 11:28:39

    1.GetCellData函数 

      作用:获取单元格的值

      例:  rowCount = Browser("xxx ").Page("xxx ").Frame("xxx").WebTable("xxx").RowCount
    'y?6P6o&u4O Q218905For counter = 1 To rowCount51Testing软件测试网u%W9\afj @'^W
      text = Browser("xxx").Page("xxx").Frame("xxx").WebTable("xxx").GetCellData(counter,1)
    D"fM^3S^k-DO218905  If (text = "xxx") Then
    Vl H$uwhF]218905    counter = counter - 151Testing软件测试网2W&e4M)? A
        selectNO = "#" & counter51Testing软件测试网WwHoL(@ C
        Browser("xxx").Page("xxx").Frame("xxx").WebRadioGroup("xxx").Select selectNO51Testing软件测试网Q;PIL&{+AM3{
        Exit For
    mhd9];O s2V*Zw218905  End If51Testing软件测试网*Ee3S|&P.KMC
    Next

    2.把值插入datatable里

      例:   datatable.setcurrentrow(i) 51Testing软件测试网 K$UG7t/vs'`X!l/w
            datatable.value("name","Global")="name"
    I9v*O%hUo218905        datatable.value("passwd","Global")="passwd"

    3.用代码来启动浏览器

      Browser1 = "IE"
    V5]f6w+N6X"W;c6g218905  StartURL = "www.51testing.com"51Testing软件测试网.tW.`3NF,Ch
      IF Browser1 = "IE" THEN
    _Na2QO&L*{!X218905     set IE = CreateObject("InternetExplorer.Application")51Testing软件测试网k9DLs"}x+hl
         IE.Visible = true51Testing软件测试网*~[+O a%B1cC
         IE.Navigate StartURL
    ._9z&ibG6J4b:t218905  END IF
    g"n-n:R X"VeR Z218905 

    4.ExecuteFile函数

      作用:ExecuteFile 可以直接执行vbs文件,而不需要将其导入resource中 
    %?z/a$M;A3M n218905       ExecuteFile FileName 
    3TM-d%H P ^.^v218905  说明:where FileName is the absolute or relative path of your VBscrīpt file.

      例:ExecuteFile("F:\test.vbs")

    5.Strcomp函数 

      作用:比较文本

      例:dim strtext1,strtext2,str ,str1,comp151Testing软件测试网4l6BU XLvnG
         strtext1 = "xxx"
    %pCG6M]k218905     strtext2 = "xxx"51Testing软件测试网qZ0X9{\
         str = VbWindow("xxx").VbWindow("xxx").VbLabe1("xxx").GetTOProperty("text")
    :Y3G6o$hx4U218905     str1= VbWindow("xxx").VbWindow("xxx").VbLabel("xxx").GetTOProperty("text")51Testing软件测试网4{0b(J l&Lng|aG
         comp1=strcomp(strtext1,str,0)51Testing软件测试网W:lu&g U:^ tcU
         If  comp=0 Then
    "D@Y)?/DL/bm218905          msgbox “这两个串相等”
    1PY!z1\-DpB218905     else
    ~0L2p"GEM218905       msgbox str51Testing软件测试网OCt |'Oko5B(JA0^#G$^
         End If 

    6.CaptureBitmap 

      作用:捕获屏幕

    7. GetROProperty

      作用:取对象属性值

      例:VbWindow("xxx").VbWindow("xxx").VbWindow("xxx").ActiveX("xxx").GetROProperty("TextMatrix(1,0)") 

    8.ExitAction - 退出当前操作,无论其循环属性如何。51Testing软件测试网!{0Wu8niP3U
      ExitActionIteration - 退出操作的当前循环。
    J g Q"T2HV+x4U218905  ExitRun - 退出测试,无论其循环属性如何。51Testing软件测试网q{|p#jx
      ExitGlobalIteration - 退出当前全局循环。

    51Testing软件测试网[9l;L+X(E)r Dh
    9.如何使用Excel对象处理数据? 51Testing软件测试网g.II b5?*?.[TY^
      Dim xl51Testing软件测试网 @6[oe O-]'Lb
      打开excel文件
    Zm3M-kymIs218905  Function OpenExcelFile(strFilePath)51Testing软件测试网W7d6z{(r pOs T
      Set xl = CreateObject("Excel.Application")51Testing软件测试网d:rY)iN^8V9A
      xl.Workbooks.Open strFilePath51Testing软件测试网 Ot de1yV&H#J g6L
      End Function51Testing软件测试网2a B}C;n'M
      获得指定单元格数据
    %IXg,a;[s4eY U218905  Function GetCellData(strSheet,rwIndex,colIndex)51Testing软件测试网z/dv#]`%UP0S7x
      GetCellData = xl.WorkSheets(strSheet).Cells(rwIndex,colIndex)51Testing软件测试网ZA&x"k q0]*~
      End Function
    J ^JOu)V218905  填充单元格数据
    dz C1RZf7?%B`218905  Function PutCellData(strSheet,rwIndex,colIndex,varData)
    R0n)^&\0Q218905  xl.WorkSheets(strSheet).Cells(rwIndex,colIndex) = varData
    4i yd*K]218905  End Function51Testing软件测试网5R5A~FRCg[.@dm
      保存并推出51Testing软件测试网!Q&NR9`-o7n ^~
      Function SaveAndQuit()
    l a ^ U2E4V@-U&h218905  xl.Activeworkbook.save51Testing软件测试网K0_OdFDX*PZ
      xl.Quit
    4S1X qWE218905  Set xl = nothing51Testing软件测试网7C;Jj-Q1Pr]
      End Function51Testing软件测试网 j&N.GJ7@C;Y _

    10.连接sql数据库

      例:Dim res,cmd,sql51Testing软件测试网kgQPlL7Ox+v
         Set Res=createobject("adodb.recordset")51Testing软件测试网9e*x(I gel8m
         Set Cmd=createobject("adodb.command")51Testing软件测试网 Uw3QI ue
         Cmd.activeconnection="Provider=SQLOLEDB.1;Password=111111;Persist Security Info=True;User ID=sa;Initial Catalog=xhq;Data Source=192.168.191.142"  '这句话是连接数据库的数据源,要做修改
    S9])Pj)O9pdF218905    Cmd.CommandType = 1
    ~]$T_{7xF!}218905    sql="selec t * from 表 where name=username"
    R|0K7} O ~218905    Cmd.CommandText = sql51Testing软件测试网1TP'PQw&H4X
        Set res = Cmd.Execute()
    bTv,c;`218905    Set res = nothing51Testing软件测试网IDJ8@5P&in6ap;a
        Set cmd.ActiveConnection = nothing
    ;_q DGU K7x\218905    Set Cmd= nothing


  • 【转载】学习QTP三部曲

    2008-10-13 11:27:44

    循序渐进学习QTP--初级篇
    6}8K_ ai'F65054      我们使用QTP的目的是想用它来执行重复的手动测试,主要是用于回归测试和测试同一软件的新版本。因此你在测试前要考虑好如何对应用程序进行测试,例如要测试那些功能、操作步骤、输入数据和期望的输出数据等。
    O+BN(i2e9U65054      强烈建议你按照版主oldsidney 写的 Tutorial_oldsidney_cn.pdf 文件来认认真真、从头到尾地执行一遍,包括录制脚本、分析脚本、增加check point、Split Action等。我想这会减少你在学习QTP过程中的不少困惑和疑虑。51Testing软件测试网~c$?"T;qS#LG
          这篇文档对如何使用QTP写的非常详细,是QTP初学者的经典教材。我就是看了这篇文档后才对QTP的整个测试流程有了一个初步的认识。在此,我对oldsidney表示感谢。51Testing软件测试网4x NU x$z[%y
         注意:51Testing软件测试网 f4rS T$GpKe
          1,确保你的IE运行正常,依次点击菜单 查看 --> 工具栏,一定要上网助手等插件卸载掉,特别3721这个垃圾网站和其它拦截广告的插件(它也把测试过程中弹出的窗口当成广告,一样会拦截的!)!
    9rhFU u;~!~;J_/V65054    2,如果是按照Tutorial_oldsidney_cn.pdf 文件 中的订购飞机票的例子来练习 QTP的使用,那么只需选择Web 插件就可以了。如果是测试其它的应用程序或系统,就要根据需要来选择相应的插件了。

    循序渐进学习QTP---中级篇

    在这个阶段你就要自己针对某个系统去录制脚本、维护脚本了。在录制后的回放过程中,你可能会遇到各种问题,这个时候就需要发挥你的主观能动性来解决遇到的问题。我想你可以按照下面的方法去解决:51Testing软件测试网3~-g@1Bc.zFb%g;R

    ~6|U,xuV9k y L65054       1,查看QTP的有关文档,包括Help 、QTP User’s Guide等文档。这些都是比较系统全面的学习材料。你该好好利用呀。
    O.G4f9N3d j&{65054       2,在本论坛上查看以前别人是如何解决此类问题的(如果有的话)或者是发新贴寻求帮助,也可以搜索Google 等网站寻找问题的解决方法;51Testing软件测试网)u0h.MR4IZ
          3,与自己部门的同事交流,例如与测试人员交流他们是如何解决的,与开发人员交流某个QTP无法识别的控件具体是用什么属性来识别的等。毕竟他们对测试的环境和测试的软件比论坛上的人熟悉呀。51Testing软件测试网3c1}G6UU _6K&iI
          4,自己通过学习VBscrīpt 等方式来提高自己的管理QTP scrīpt的能力。
    f N9U"p-V:o6505451Testing软件测试网%^R,T]cg~bT
    或许你会发现许多问题都是由提出问题的人来解决的,因为他们希望问题得到解决的迫切心比谁都强烈。

    循序渐进学习QTP---高阶篇

    如果你对VB scrīpt 、QTP和需要测试的程序或系统非常熟悉,你可能就想直接写QTP scrīpt来表现一下了。如果你能达到这个水平,那么恭喜你---你就是真正的高手了。这个时候你已经可以从宏观上把握QTP了,也能灵活自如地使用QTP了。51Testing软件测试网*V2|zb7w_)pI
  • 如何用QTP解决图片验证码(解析QuickTest文本识别机制)?【转】

    2008-10-13 11:27:14

    大家在使用QTP进行自动化测试的过程中经常会遇到图片验证码的问题——大家所关心的就是如何解决此类问题。51Testing软件测试网4Xi0[3b;g` h
    这里我们首先要去了解为什么会有图片验证码。其实验证码的本质作用就是防止有人利用工具(灌水机、注册机,当然也不小心包括了我们的自动化测试工具)恶意猜解登陆或者不停的注册和灌水的。因此如果我们完全寄希望于通过GUI识别来获取内容是不切实际的——先打好预防针,免得读者希望太大,失望更大,呵呵!
    ls6M%w;q65054 下面说说验证码的解决思路:
    h8A*Rod65054 其实解决图片验证码的思路有很多,我这里主要结合QTP9.5的新特性给大家介绍其中一种解决方案,就是利用它的OCR机制抓取文本内容。
    |/H^3S.b.M-AT65054 在QTP9.5中,对象识别能力有了进一步改善,其中针对文本识别方面进行了优化,引入了ABBYY公司的OCR解决方案——这个相关的功能体现在QTP菜单的“Tools-->Options-->General--Use text recognition mechanisms in this order”里,详细内容后面会有具体介绍。51Testing软件测试网,W\3Y0a^l
    先来看看ABBYY是何许公司,登录他们的官方网站可以看到一段相关介绍:“ABBYY是世界OCR(光学字符识别)、ICR(手写体识别)和语言软件的领航者。ABBYY 致力于人工智能(AI)和语言软件开发。提供全套文档识别,转换和数据捕获技术的产品解决方案。”如果你使用过图像文档转换的软件,一定会听说过FineReader OCR Professional ,其实它就是ABBYY公司的产品,用官方的说法就是“将通过扫描仪、MFP 或数码相机生成的图像快速转换为可编辑和可搜索的电子格式,而且识别率很高”,说白了就是可以借助它先进的OCR机制“读”出图片里的文本内容,并转换为PDF之类的文档。51Testing软件测试网3LI FU2iR
    有了ABBYY这么强大的背后支持,QTP自然底气十足,那么QTP到底如何以OCR机制识别文本呢?我们首先先了解一下什么是OCR。
    -T4w_H3T65054 打开“百度百科_OCR”,它的说明:“OCR(Optical Character Recognition,光学字符识别),是属于图型识别(Pattern Recognition,PR)的一门学问。其目的就是要让计算机知道它到底看到了什么,尤其是文字资料。 由于OCR是一门与识别率拔河的技术,因此如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题,ICR(Intelligent Character Recognition)的名词也因此而产生。而根据文字资料存在的媒体介质不同,及取得这些资料的方式不同,就衍生出各式各样、各种不同的应用。”这里有个关键词:“正确率”,也就是“识别率”——既然不能够总是100%,我们自然不可能完全寄希望于通过QTP能够每次100%正确的去识别图片里的文本。尤其是“道高一尺魔高一丈”的今天,验证码加入了大量的干扰素,如扭曲、变形、错位、随机背景花纹,给OCR识别增加了很多难度——本来就不希望被软件识别到嘛。51Testing软件测试网8M LB~[

    'FT7G7@XtNCL-~%q65054 了解了OCR之后,我们再来看看QTP对应的这个设置。如前面所说,通过QTP菜单的“Tools-->Options”选中到“General--Use text recognition mechanisms in this order”,这里的四个选项就是对应的不同设置。我们看看帮助的描述(我做了翻译):
    1E5FYFU[J"Z65054 =================================
    k/t0wAWy6lK65054 使用文本识别机制
    Y(WZ e[3l5b ? `I65054 51Testing软件测试网`3~tTN}
    指定QTP在采用 “文本”或者“文本区域” 的 检查点或输出值 的步骤时,捕获文本内容所使用的文本识别机制。
    bty O:mi }65054 以下有三种识别方式:51Testing软件测试网]%Yx(t'Z#[F%\*nUB
    1、先使用Windows API,再使用OCR(默认)。
    [ j[$sH(j65054     指示QTP首先尝试以基于Windows API的机制从对象上直接获取文本内容。如果未获取到文本(比如,文本属于图片的一部分),QTP就会使用OCR的机制尝试获取这段文本。
    7H(X2EDQ$YF*Et65054     强烈建议在使用中日韩(象形文字)、英的语言环境下采用这个设置。
    L!U V^:e7R3Xp;l,cOu65054
    CR,E~G'Q[65054 2、先使用OCR,再使用Windows API。
    ;r-b5C4`#Q&U9]2b8A%x65054     指示QTP首先尝试使用OCR机制从对象上去获取文本。如果未获取到文本,QTP就会以Windows API的机制去获取文本内容。51Testing软件测试网%R[Pv_

    -E T6C8yze65054 3、仅使用Windows API方式。51Testing软件测试网p2G8[:sg(R]4l
        指示QTP仅采用基于Windows API的机制从对象上获取文本内容。51Testing软件测试网![4K2r9v9Rj Le6u'K@

    h@[)N)h\[65054 4、仅使用OCR的方式。
    P G)WX~a5r:^ H65054     指示QTP仅采用基于OCR的机制从对象上获取文本内容。51Testing软件测试网jPQLs\
        在使用Windows Vista要使用这种方式。
    S'N {c2uU)L65054
    4TnQh6}w65054 =================================
    6U9s7b6J*U)|[l K65054 上面的内容已经解释的很明确了,接下来我们通过TextArea Output Value看看效果。51Testing软件测试网 xf;\/DQ
    51Testing软件测试网+s,V8igtRb
    如下图所示,QTP针对几张图片的识别效果:51Testing软件测试网8w-[ X&h,S g
    (一)、内容是51Testing的,QTP获取正确;内容是51Testing的G风格彩字,QTP获取错误(显示为IC_CHECK_PATTERN)51Testing软件测试网`%vG9}Zs[ `O.w
    51Testing软件测试网zz k+K;N'[
    51Testing软件测试网0dv }_f$FKE
    51Testing软件测试网vw+n"d%~L;w kj ]
    (二)、内容是songfun的普通文本,QTP获取正确;内容是songfun的G风格彩字,QTP获取错误(也显示为IC_CHECK_PATTERN)
    ek ??sO6F$aSK65054 51Testing软件测试网!dN?srX Q F

    )b2E]va F.q65054
    D5AY3Pa*Ni7cJ`65054 51Testing软件测试网R\BHi2wJM
    有兴趣大家可以自己做一些图片,甚至可以用QQ的验证码图片来试验一下,看看OCR效果。
  • google test【转】

    2008-10-10 16:02:15

    Introduction:为什么需要Google C++ 测试框架?

     

    Google C++ 测试框架帮助你更好地编写C++测试。

     

    无论你是在Linux,Windows,还是Mac环境下工作,只要你编写C++代码,Google 测试框架都可以帮上忙。

     

    那么,哪些因素才能构成一个好的测试?以及,Google C++ 测试框架怎样满足这些因素?我们相信:

    1. 测试应该是独立可重复的。因为其他测试成功或失败而导致我们要对自己的测试进行debug是非常痛苦的。Google C++ 测试框架通过将每个测试在不同的对象中运行,使得测试分离开来。当一个测试失败时,Google C++ 测试框架允许你独立运行它以进行快速除错。
    2. 测试应该能够被很好地组织,并反映被测代码的结构。Google C++ 测试框架将测试组织成测试案例,案例中的测试可以共享数据和程序分支。这样一种通用模式能够很容易辨识,使得我们的测试容易维护。当开发人员在项目之间转换,开始在一个新的代码基上开始工作时,这种一致性格外有用。
    3. 测试应该是可移植可重用的。开源社区有很多平台独立的代码,它们的测试也应该是平台独立的。除开一些特殊情况,Google C++ 测试框架运行在不同的操作系统上、与不同的编译器(gcc、icc、MSVC)搭配,Google C++ 测试框架的测试很容易与不同的配置一起工作。
    4. 当测试失败时,应该提供尽可能多的、关于问题的信息Google C++ 测试框架在第一个测试失败时不会停下来。相反,它只是将当前测试停止,然后继续接下来的测试。你也可以设置对一些非致命的错误进行报告,并接着进行当前的测试。这样,你就可以在一次“运行-编辑-编译”循环中检查到并修复多个bug。
    5. 测试框架应该能将测试编写人员从一些环境维护的工作中解放出来,使他们能够集中精力于测试的内容Google C++ 测试框架自动记录下所有定义好的测试,不需要用户通过列举来指明哪些测试需要运行。
    6. 测试应该快速。使用Google C++ 测试框架,你可以重用多个测试的共享资源,一次性完成设置/解除设置,而不用使一个测试去依赖另一测试。

    因为Google C++ 测试框架基于著名的xUnit架构,如果你之前使用过JUnit或PyUnit的话,你将会感觉非常熟悉。如果你没有接触过这些测试框架,它也只会占用你大约10分钟的时间来学习基本概念和上手。所以,让我们开始吧!

     

    Note:本文偶尔会用“Google Test”来代指“Google C++ 测试框架”。

     

    基本概念

     

    使用Google Test时,你是从编写断言开始的,而断言是一些检查条件是否为真的语句。一个断言的结果可能是成功、非致命失败,或者致命失败。如果一个致命失败出现,他会结束当前的函数;否则,程序继续正常运行。

     

    测试使用断言来验证被测代码的行为。如果一个测试崩溃或是出现一个失败的断言,那么,该测试失败;否则该测试成功

     

    一个测试案例(test case)包含了一个或多个测试。你应该将自己的测试分别归类到测试案例中,以反映被测代码的结构。当测试案例中的多个测试需要共享通用对象和子程序时,你可以把他们放到一个测试固件(test fixture)类中。

     

    一个测试程序可以包含多个测试案例。

     

    从编写单个的断言开始,到创建测试和测试案例,我们将会介绍怎样编写一个测试程序。

     

    断言

     

    Google Test中的断言是一些与函数调用相似的宏。要测试一个类或函数,我们需要对其行为做出断言。当一个断言失败时,Google Test会在屏幕上输出该代码所在的源文件及其所在的位置行号,以及错误信息。也可以在编写断言时,提供一个自定义的错误信息,这个信息在失败时会被附加在Google Test的错误信息之后。

     

    断言常常成对出现,它们都测试同一个类或者函数,但对当前功能有着不同的效果。ASSERT_*版本的断言失败时会产生致命失败,并结束当前函数。EXPECT_*版本的断言产生非致命失败,而不会中止当前函数。通常更推荐使用EXPECT_*断言,因为它们运行一个测试中可以有不止一个的错误被报告出来。但如果在编写断言如果失败,就没有必要继续往下执行的测试时,你应该使用ASSERT_*断言。

     

    因为失败的ASSERT_*断言会立刻从当前的函数返回,可能会跳过其后的一些的清洁代码,这样也许会导致空间泄漏。根据泄漏本身的特质,这种情况也许值得修复,也可能不值得我们关心——所以,如果你得到断言错误的同时,还得到了一个堆检查的错误,记住上面我们所说的这一点。

     

    要提供一个自定义的错误消息,只需要使用<<操作符,或一个<<操作符的序列,将其输入到框架定义的宏中。下面是一个例子:

     

     
    Cpp代码 复制代码
    1. ASSERT_EQ(x.size(), y.size()) << "Ve<SPAN class=hilite2>c</SPAN>tors x and y are of unequal length";   
    2. for (int i = 0; i < x.size(); ++i) {   
    3.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(x[i], y[i]) << "Ve<SPAN class=hilite2>c</SPAN>tors x and y differ at index " << i;   
    4. }  
     

    任何能够被输出到ostream中的信息都可以被输出到一个断言宏中——特别是C字符串和string对象。如果一个宽字符串(wchar_t*,windows上UNICODE模式TCHAR*或std::wstring)被输出到一个断言中,在打印时它会被转换成UTF-8编码。

     

    基本断言

     

    下面这些断言实现了基本的true/false条件测试。

     

    致命断言 非致命断言 验证条件
    ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition为真
    ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition 为假

     

    记住,当它们失败时,ASSERT_*产生一个致命失败并从当前函数返回,而EXCEPT_*产生一个非致命失败,允许函数继续运行。在两种情况下,一个断言失败都意味着它所包含的测试失败。

     

    有效平台:Linux、Windows、Mac

     

    二进制比较

     

    本节描述了比较两个值的一些断言。

     

    致命断言 非致命断言 验证条件
    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

     

    在出现失败事件时,Google Test会将两个值(Val1Val2)都打印出来。在ASSERT_EQ*和EXCEPT_EQ*断言(以及我们随后介绍类似的断言)中,你应该把你希望测试的表达式放在actual(实际值)的位置上,将其期望值放在expected(期望值)的位置上,因为Google Test的测试消息为这种惯例做了一些优化。

     

    参数值必须是可通过断言的比较操作符进行比较的,否则你会得到一个编译错误。参数值还必须支持<<操作符来将值输入到ostream中。所有的C++内置类型都支持这一点。

     

    这些断言可以用于用户自定义的型别,但你必须重载相应的比较操作符(如==、<等)。如果定义有相应的操作符,推荐使用ASSERT_*()宏,因为它们不仅会输出比较的结果,还会输出两个比较对象。

     

    参数表达式总是只被解析一次。因此,参数表达式有一定的副作用(side effect,这里应该是指编译器不同,操作符解析顺序的不确定性)也是可以接受的。但是,同其他普通C/C++函数一样,参数表达式的解析顺序是不确定的(如,一种编译器可以自由选择一种顺序来进行解析),而你的代码不应该依赖于某种特定的参数解析顺序。

     

    ASSERT_EQ()对指针进行的是指针比较。即,如果被用在两个C字符串上,它会比较它们是否指向同样的内存地址,而不是它们所指向的字符串是否有相同值。所以,如果你想对两个C字符串(例如,const char*)进行值比较,请使用ASSERT_STREQ()宏,该宏会在后面介绍到。特别需要一提的是,要验证一个C字符串是否为空(NULL),使用ASSERT_STREQ(NULL, c_string)。但是要比较两个string对象时,你应该使用ASSERT_EQ。

     

    本节中介绍的宏都可以处理窄字符串对象和宽字符串对象(string和wstring)。

     

    有效平台:Linux、Windows、Mac

     

    字符串比较

     

    该组断言用于比较两个C字符串。如果你想要比较两个string对象,相应地使用EXPECT_EQ、EXPECT_NE等断言。

     

    致命断言 非致命断言 验证条件
    ASSERT_STREQ(expected_str, actual_str); EXPECT_STREQ(expected_str, actual_str); 两个C字符串有相同的内容
    ASSERT_STRNE(str1, str2); EXPECT_STRNE(str1, str2); 两个C字符串有不同的内容
    ASSERT_STRCASEEQ(expected_str, actual_str); EXPECT_STRCASEEQ(expected_str, actual_str); 两个C字符串有相同的内容,忽略大小写
    ASSERT_STRCASENE(str1, str2); EXPECT_STRCASENE(str1, str2); 两个C字符串有不同的内容,忽略大小写

     

    注意断言名称中出现的“CASE”意味着大小写被忽略了。

     

    *STREQ*和*STRNE*也接受宽字符串(wchar_t*)。如果两个宽字符串比较失败,它们的值会做为UTF-8窄字符串被输出。

     

    一个NULL空指针和一个空字符串会被认为是不一样的。

     

    有效平台:Linux、Windows、Mac

     

    参见:更多的字符串比较的技巧(如子字符串、前缀和正则表达式匹配),请参见[Advanced Guide Advanced Google Test Guide]。

     

    简单的测试

     

    要创建一个测试:

    1. 使用TEST()宏来定义和命名一个测试函数,它们是一些没有返回值的普通C++函数。
    2. 在这个函数中,与你想要包含的其它任何有效C++代码一起,使用Google Test提供的各种断言来进行检查。
    3. 测试的结果由其中的断言决定;如果测试中的任意断言失败(无论是致命还是非致命),或者测试崩溃,那么整个测试就失败了。否则,测试通过。 
    Cpp代码 复制代码
    1. <SPAN class=hilite3>TEST</SPAN>(<SPAN class=hilite3>test</SPAN>_<SPAN class=hilite2>c</SPAN>ase_name, <SPAN class=hilite3>test</SPAN>_name) {   
    2. ... <SPAN class=hilite3>test</SPAN> body ...   
    3. }  
     

    TEST()的参数是从概括到特殊的。第一个参数是测试案例的名称,第二个参数是测试案例中的测试的名称。记住,一个测试案例可以包含任意数量的独立测试。一个测试的全称包括了包含它的测试案例名称,及其独立的名称。不同测试案例中的独立测试可以有相同的名称。

     

    举例来说,让我们看一个简单的整数函数:

     

    Cpp代码 复制代码
    1. int Fa<SPAN class=hilite2>c</SPAN>torial(int n); // 返回n的阶乘  
     

     

    这个函数的测试案例应该看起来像是:

     

    Cpp代码 复制代码
    1. // 测试0的阶乘   
    2. <SPAN class=hilite3>TEST</SPAN>(Fa<SPAN class=hilite2>c</SPAN>torial<SPAN class=hilite3>Test</SPAN>, HandlesZeroInput) {   
    3.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(1, Fa<SPAN class=hilite2>c</SPAN>torial(0));   
    4. }   
    5. // 测试正数的阶乘   
    6. <SPAN class=hilite3>TEST</SPAN>(Fa<SPAN class=hilite2>c</SPAN>torial<SPAN class=hilite3>Test</SPAN>, HandlesPositiveInput) {   
    7.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(1, Fa<SPAN class=hilite2>c</SPAN>torial(1));   
    8.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(2, Fa<SPAN class=hilite2>c</SPAN>torial(2));   
    9.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(6, Fa<SPAN class=hilite2>c</SPAN>torial(3));   
    10.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(40320, Fa<SPAN class=hilite2>c</SPAN>torial(8));   
    11. }  
     

     

    Google Test根据测试案例来分组收集测试结果,因此,逻辑相关的测试应该在同一测试案例中;换句话说,它们的TEST()的第一个参数应该是一样的。在上面的例子中,我们有两个测试,HandlesZeroInput和HandlesPostiveInput,它们都属于同一个测试案例FactorialTest

     

    有效平台:Linux、Windows、Mac

     

    测试固件(Test Fixtures,又做测试夹具、测试套件):在多个测试中使用同样的数据配置

     

    当你发现自己编写了两个或多个测试来操作同样的数据,你可以采用一个测试固件。它让你可以在多个不同的测试中重用同样的对象配置。

     

    要创建测试固件,只需:

    1. 创建一个类继承自testing::Test。将其中的成员声明为protected:或是public:,因为我们想要从子类中存取固件成员。
    2. 在该类中声明你计划使用的任何对象。
    3. 如果需要,编写一个默认构造函数或者SetUp()函数来为每个测试准备对象。常见错误包括将SetUp()拼写为Setup()(小写了u)——不要让它发生在你身上。
    4. 如果需要,编写一个析构函数或者TearDown()函数来释放你在SetUp()函数中申请的资源。要知道什么时候应该使用构造函数/析构函数,什么时候又应该使用SetUp()/TearDown()函数,阅读我们的FAQ。
    5. 如果需要,定义你的测试所需要共享的子程序。

    当我们要使用固件时,使用TEST_F()替换掉TEST(),它允许我们存取测试固件中的对象和子程序:

     

    Cpp代码 复制代码
    1. <SPAN class=hilite3>TEST</SPAN>_F(<SPAN class=hilite3>test</SPAN>_<SPAN class=hilite2>c</SPAN>ase_name, <SPAN class=hilite3>test</SPAN>_name) {   
    2. ... <SPAN class=hilite3>test</SPAN> body ...   
    3. }  

     

    TEST()一样,第一个参数是测试案例的名称,但对TEST_F()来说,这个名称必须与测试固件类的名称一些。你可能已经猜到了:_F正是指固件。

     

    不幸地是,C++宏系统并不允许我们创建一个单独的宏来处理两种类型的测试。使用错误的宏会导致编译期的错误。

     

    而且,你必须在TEST_F()中使用它之前,定义好这个测试固件类。否则,你会得到编译器的报错:“virtual outside class declaration”。

    对于TEST_F()中定义的每个测试,Google Test将会:

    1. 在运行时创建一个全新的测试固件
    2. 马上通过SetUp()初始化它,
    3. 运行测试
    4. 调用TearDown()来进行清理工作
    5. 删除测试固件。注意,同一测试案例中,不同的测试拥有不同的测试固件。Google Test在创建下一个测试固件前总是会对现有固件进行删除。Google Test不会对多个测试重用一个测试固件。测试对测试固件的改动并不会影响到其他测试。

    例如,让我们为一个名为Queue的FIFO队列类编写测试,该类的接口如下:

     
    Cpp代码 复制代码
    1. template <typename E> // E为元素类型   
    2. <SPAN class=hilite2>c</SPAN>lass Queue {   
    3. publi<SPAN class=hilite2>c</SPAN>:   
    4.   Queue();   
    5.   void Enqueue(<SPAN class=hilite2>c</SPAN>onst E& element);   
    6.   E* Dequeue(); // 返回 NULL 如果队列为空.   
    7.   size_t size() <SPAN class=hilite2>c</SPAN>onst;   
    8.   ...   
    9. };  

     

    首先,定义一个固件类。习惯上,你应该把它的名字定义为FooTest,这里的Foo是被测试的类。

     
    Cpp代码 复制代码
    1. <SPAN class=hilite2>c</SPAN>lass Queue<SPAN class=hilite3>Test</SPAN> : publi<SPAN class=hilite2>c</SPAN> <SPAN class=hilite3>test</SPAN>ing::<SPAN class=hilite3>Test</SPAN> {   
    2. prote<SPAN class=hilite2>c</SPAN>ted:   
    3.   virtual void SetUp() {   
    4.     q1_.Enqueue(1);   
    5.     q2_.Enqueue(2);   
    6.     q2_.Enqueue(3);   
    7.   }   
    8.   // virtual void TearDown() {}   
    9.   Queue<int> q0_;   
    10.   Queue<int> q1_;   
    11.   Queue<int> q2_;   
    12. };  
     

    在这个案例中,我们不需要TearDown(),因为每个测试后除了析构函数外不需要进行其它的清理工作了。

     

    接下来我们使用TEST_F()和这个固件来编写测试。

     

    Cpp代码 复制代码
    1. <SPAN class=hilite3>TEST</SPAN>_F(Queue<SPAN class=hilite3>Test</SPAN>, IsEmptyInitially) {   
    2.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(0, q0_.size());   
    3. }   
    4. <SPAN class=hilite3>TEST</SPAN>_F(Queue<SPAN class=hilite3>Test</SPAN>, DequeueWorks) {   
    5.   int* n = q0_.Dequeue();   
    6.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(NULL, n);   
    7.   
    8.   n = q1_.Dequeue();   
    9.   ASSERT_TRUE(n != NULL);   
    10.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(1, *n);   
    11.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(0, q1_.size());   
    12.   delete n;   
    13.   
    14.   n = q2_.Dequeue();   
    15.   ASSERT_TRUE(n != NULL);   
    16.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(2, *n);   
    17.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(1, q2_.size());   
    18.   delete n;   
    19. }  
     

    上面这段代码既使用了ASSERT_*断言,又使用了EXPECT_*断言。经验上讲,如果你想要断言失败后,测试能够继续进行以显示更多的错误时,你应该使用EXPECT_*断言;使用ASSERT_*如果该断言失败后继续往下执行毫无意义。例如,Dequeue测试中的第二个断言是ASSERT_TURE(n!= NULL),因为我们随后会n指针解引用,如果n指针为空的话,会导致一个段错误。

     

    当这些测试开始时,会发生如下情况:

    1. Google Test创建一个QueueTest对象(我们把它叫做t1)。
    2. t1.SetUp()初始化t1。
    3. 第一个测试(IsEmptyInitiallly)在t1上运行。
    4. 测试完成后,t1.TearDown()进行一些清理工作。
    5. t1被析构。
    6. 以上步骤在另一个QueueTest对象上重复进行,这回会运行DequeueWorks测试。

    有效平台:Linux、Windows、Mac

     

    注意:当一个测试对象被构造时,Google Test会自动地保存所有的Google Test变量标识,对象析构后进行恢复。

     

    调用测试

     

    TEST()和TEST_F()向Google Test隐式注册它们的测试。因此,与很多其他的C++测试框架不同,你不需要为了运行你定义的测试而将它们全部再列出来一次。

     

    在定义好测试后,你可以通过RUN_ALL_TESTS()来运行它们,如果所有测试成功,该函数返回0,否则会返回1.注意RUN_ALL_TESTS()会运行你链接到的所有测试——它们可以来自不同的测试案例,甚至是来自不同的文件。

     

    当被调用时,RUN_ALL_TESTS()宏会:

    1. 保存所有的Google Test标志。
    2. 为一个侧测试创建测试固件对象。
    3. 调用SetUp()初始化它。
    4. 在固件对象上运行测试。
    5. 调用TearDown()清理固件。
    6. 删除固件。
    7. 恢复所有Google Test标志的状态。
    8. 重复上诉步骤,直到所有测试完成。

    此外,如果第二步时,测试固件的构造函数产生一个致命错误,继续执行3至5部显然没有必要,所以它们会被跳过。与之相似,如果第3部产生致命错误,第4部也会被跳过。

     

    重要:你不能忽略掉RUN_ALL_TESTS()的返回值,否则gcc会报一个编译错误。这样设计的理由是自动化测试服务会根据测试退出返回码来决定一个测试是否通过,而不是根据其stdout/stderr输出;因此你的main()函数必须返回RUN_ALL_TESTS()的值。

     

    而且,你应该只调用RUN_ALL_TESTS()一次。多次调用该函数会与Google Test的一些高阶特性(如线程安全死亡测试thread-safe death tests)冲突,因而是不被支持的。

     

    有效平台:Linux、Windows、Mac

     

    编写main()函数

     

    你可以从下面这个样板开始:

     

    Cpp代码 复制代码
    1. #in<SPAN class=hilite2>c</SPAN>lude "this/pa<SPAN class=hilite2>c</SPAN>kage/foo.h"   
    2. #in<SPAN class=hilite2>c</SPAN>lude <g<SPAN class=hilite3>test</SPAN>/g<SPAN class=hilite3>test</SPAN>.h>   
    3. namespa<SPAN class=hilite2>c</SPAN>e {   
    4. // 测试Foo类的测试固件   
    5. <SPAN class=hilite2>c</SPAN>lass Foo<SPAN class=hilite3>Test</SPAN> : publi<SPAN class=hilite2>c</SPAN> <SPAN class=hilite3>test</SPAN>ing::<SPAN class=hilite3>Test</SPAN> {   
    6. prote<SPAN class=hilite2>c</SPAN>ted:   
    7.   // You <SPAN class=hilite2>c</SPAN>an remove any or all of the following fun<SPAN class=hilite2>c</SPAN>tions if its body   
    8.   // is empty.   
    9.   Foo<SPAN class=hilite3>Test</SPAN>() {   
    10.     // You <SPAN class=hilite2>c</SPAN>an do set-up work for ea<SPAN class=hilite2>c</SPAN>h <SPAN class=hilite3>test</SPAN> here.   
    11.   }   
    12.   virtual ~Foo<SPAN class=hilite3>Test</SPAN>() {   
    13.     // You <SPAN class=hilite2>c</SPAN>an do <SPAN class=hilite2>c</SPAN>lean-up work that doesn't throw ex<SPAN class=hilite2>c</SPAN>eptions here.   
    14.   }   
    15.   // If the <SPAN class=hilite2>c</SPAN>onstru<SPAN class=hilite2>c</SPAN>tor and destru<SPAN class=hilite2>c</SPAN>tor are not enough for setting up   
    16.   // and <SPAN class=hilite2>c</SPAN>leaning up ea<SPAN class=hilite2>c</SPAN>h <SPAN class=hilite3>test</SPAN>, you <SPAN class=hilite2>c</SPAN>an define the following methods:   
    17.   virtual void SetUp() {   
    18.     // <SPAN class=hilite2>C</SPAN>ode here will be <SPAN class=hilite2>c</SPAN>alled immediately after the <SPAN class=hilite2>c</SPAN>onstru<SPAN class=hilite2>c</SPAN>tor (right   
    19.     // before ea<SPAN class=hilite2>c</SPAN>h <SPAN class=hilite3>test</SPAN>).   
    20.   }   
    21.   virtual void TearDown() {   
    22.     // <SPAN class=hilite2>C</SPAN>ode here will be <SPAN class=hilite2>c</SPAN>alled immediately after ea<SPAN class=hilite2>c</SPAN>h <SPAN class=hilite3>test</SPAN> (right   
    23.     // before the destru<SPAN class=hilite2>c</SPAN>tor).   
    24.   }   
    25.   // Obje<SPAN class=hilite2>c</SPAN>ts de<SPAN class=hilite2>c</SPAN>lared here <SPAN class=hilite2>c</SPAN>an be used by all <SPAN class=hilite3>test</SPAN>s in the <SPAN class=hilite3>test</SPAN> <SPAN class=hilite2>c</SPAN>ase for Foo.   
    26. };   
    27.   
    28. // <SPAN class=hilite3>Test</SPAN>s that the Foo::Bar() method does Ab<SPAN class=hilite2>c</SPAN>.   
    29. <SPAN class=hilite3>TEST</SPAN>_F(Foo<SPAN class=hilite3>Test</SPAN>, MethodBarDoesAb<SPAN class=hilite2>c</SPAN>) {   
    30.   <SPAN class=hilite2>c</SPAN>onst string input_filepath = "this/pa<SPAN class=hilite2>c</SPAN>kage/<SPAN class=hilite3>test</SPAN>data/myinputfile.dat";   
    31.   <SPAN class=hilite2>c</SPAN>onst string output_filepath = "this/pa<SPAN class=hilite2>c</SPAN>kage/<SPAN class=hilite3>test</SPAN>data/myoutputfile.dat";   
    32.   Foo f;   
    33.   EXPE<SPAN class=hilite2>C</SPAN>T_EQ(0, f.Bar(input_filepath, output_filepath));   
    34. }   
    35.   
    36. // <SPAN class=hilite3>Test</SPAN>s that Foo does Xyz.   
    37. <SPAN class=hilite3>TEST</SPAN>_F(Foo<SPAN class=hilite3>Test</SPAN>, DoesXyz) {   
    38.   // Exer<SPAN class=hilite2>c</SPAN>ises the Xyz feature of Foo.   
    39. }   
    40. }  // namespa<SPAN class=hilite2>c</SPAN>e   
    41.   
    42. int main(int arg<SPAN class=hilite2>c</SPAN>, <SPAN class=hilite2>c</SPAN>har **argv) {   
    43.   <SPAN class=hilite3>test</SPAN>ing::Init<SPAN class=hilite1>Google</SPAN><SPAN class=hilite3>Test</SPAN>(&arg<SPAN class=hilite2>c</SPAN>, argv);   
    44.   return RUN_ALL_<SPAN class=hilite3>TEST</SPAN>S();   
    45. }  
  • Bugfree安装问题解决方案

    2008-10-10 15:49:15

    【摘自小水滴的个人空间】

      总结一下我在安装Bugfree时遇到的一些问题和相关的解决方案

    服务器端环境:

    操作系统:RedHat AS 4 ;数据库:Mysql;Web服务器:Apache;脚本系统:Php

    错误提示一:不能通过'/tmp/mysql.sock'连到服务器

    解决方案:这个问题是用户权限不够造成的,数据库里赋予用户足够权限即可解决。具体操作方法如

    下:

    [root@localhost etc]# mysql

    Welcome to the MySQL monitor. Commands end with ; or \g.

    Your MySQL connection id is 7 to server version: 4.1.16

     

    mysql> grant all privileges on *.* to 'jifang'@'' identified by 'hello';

    Query OK, 0 rows affected (0.01 sec)

     

    mysql> flush privileges;

    Query OK, 0 rows affected (0.00 sec)

     

    mysql> exit

    Bye

     

    [root@localhost etc]# mysql

    Welcome to the MySQL monitor. Commands end with ; or \g.

    Your MySQL connection id is 9 to server version: 4.1.16

     

    mysql> use mysql

    Reading table information for completion of table and column names

    You can turn off this feature to get a quicker startup with -A

     

    Database changed

     

    mysql> select * from user;

     

    mysql> exit

    Bye

     

    错误提示二:客户机浏览器显示的是php的源码

     

    解决方案:只需要重起Apache,即可解决。具体操作方法如下:

     

    ]#cd /path/to/apache/bin
    ]#apachectl restart
    or
    ]#servcice httpd restart

     

    错误提示三:目录下找不到mysql.sock

     

    解决方案:重新启动Mysql。命令执行完成后,需要等待一段时间,才能有

     

    mysql.sock生成。具体操作方法如下:

     

    1、使用 service 启动:service mysqld restart

     

    2、使用 mysqld  脚本启动:/etc/inint.d/mysqld restart

     

我的存档

数据统计

  • 访问量: 6650
  • 日志数: 11
  • 建立时间: 2008-10-09
  • 更新时间: 2008-10-13

RSS订阅

Open Toolbar