发布新日志

  • 通过缓存对象路径的方式提高RFT的对象识别效率

    2012-10-15 20:01:26Top 2 Digest 2

    又是漫漫长夜,无心睡眠……这次文章是技术总结,不是随想,所以省去开头和暖场,直接切入正题。本文档对于如何使用RFT+XPATH提高自动化测试的执行效率提供了一种新的思路,就是缓存对象路径,(PS:没用过RFT做自动化测试的同学可以忽略了 ,用watir的同学也可以忽略了。)

    界面对象识别及维护的费效比是UI自动化测试永远的话题

    UI层的自动化测试,提高脚本的执行效率是永远的主题,我们必须把一轮脚本的执行时间控制在可接受的范围内,当脚本的总体执行时间很长时,我们就需要对其进行优化,优化的方法无非是三种,1、优化用例,减少无效用例的个数;2、提高脚本识别UI对象的效率;3、分布式执行。本文介绍的方法属于第二种,提高脚本识别UI对象的效率

    什么是RFT

    RFTIBM的一款自动化测试工具,它的作用和QTP类似,使用JAVA作为脚本语言,ECLIPSE作为IDE,优雅并且强大。RFT识别对象的核心方法是RootTestObjectfind方法。我们做自动化测试的时候,通过对FIND方法的封装实现了自己的对象识别框架。但是find方法的执行效率问题一直是我的心病。之前的情况是查找对象时,执行一次find方法至少要4-6秒的时间,几百个用例执行下来执行时间就让人无法忍受了,十几个小时……只能晚上跑脚本,早上来看结果,真赶到上午发版的时候,根本指望不上自动化测试能帮上什么忙,所以必须要想办法缩短脚本执行的总体时间,提高对象的识别效率。

    什么是XPATH

    XPATH是一种XML的查询语言。简洁,高效。在IBM的开发者社区论坛里,有专门的一篇文章讲解如何结合RFT+XPATH来实现动态识别对象,很赞。这里给出文章的链接:《使用 XPath 在 Rational Functional Tester 中动态识别对象》,作者刘哲,段雪飞,邢静。在此表示感谢并崇拜一下。另外多说一下,IBM的开发者社区真的很有料,他们的文档库里关于自动化测试的文章建议大家通读,保证你获益匪浅。

    XPATH识别对象的效率明显优于find方法,为什么?原因在于XPATH查找对象是基于某个对象的具体路径,而find方法是动态查找,也就是全局查找,这样遍历的对象多,必然就慢。举一个xpath的例子,来源于刚才的那篇文章,对于对象,使用XPATH来查找时路径可能是:"org.eclipse.swt.widgets.Shell[@captionText=

         'Hello']/org.eclipse.swt.widgets.Button[@text='OK']"),而使用rftfind方法如果想实现同样的效果,就只能用atChild来拼了。写过RFT脚本的同学应该都有体会,事实上,如果在xpath中不使用路径而直接传入/::desander[@captionText='Hello'],那么他的执行效率和find的全局查找是类似的。

    问题及解决方案

    但是XPATH虽然快,可是仍然有缺点,那就是路径的维护问题。在一个自动化测试工程中,我们可能会使用到近百个测试对象,我们当然可以把每个对象的XPATH路径存到文本文件里,但问题是,如果程序的页面结构发生变化了,怎么办,这么多的缓存路径改起来不是闹着玩的,而且排查错误也不容易。所以我一直在寻找一种方法,能结合RFT动态识别和XPATH效率快两个优点,并且维护简单,后来就有了这个想法:把一个测试对象的父对象的class属性依次读取出来,拼成该对象的一个路径并写入到缓存文件中,当脚本在识别对象时,首先从缓存文件中把路径读取出来,并传递给XPATH去识别,如果对象能识别到,则执行操作;如果识别不到,则重新执行find方法进行识别,并把识别到的对象的路径重新更新到缓存路径中,如果find方法也找不到对象,就返回null,此时就需要人工介入排查识别的原因了。这种做法就是我标题中提到缓存对象路径的作法。

    关于缓存文件的存储格式,我采用的策略是为每一个UI层的测试对象分配唯一个的objectID作为标识。规则是脚本名称 + object_id + objecg_value。其中object_id和object_value是你在识别测试对象时使用的属性。写过RFT脚本的同学应该都懂,不懂的就给我发私信吧,因为也不是一句两句能解释清楚的,毕竟这不是一篇教程,大家见谅;

    缓存对象路径的做法,其实核心就是两点:

    1、在识别测试对象时,永远先从缓存文件中读取对象路径并由XPATH识别;

    2、当路径失效或者不存在时,由自动化测试代码自动更新路径,不然想自己手写XPATH路径的同学您最好先考虑清楚。

    以下是几个核心代码的实现,供大家参考。(PS:想要直接拷代码的同学可以忽略下面的内容了,因为你没有这些代码底层的支持代码,拷过去也没用的)

    通过递归读取对象路径的方法:

    private void addPropertyToCatch(TestObject to, StringBuffer str) { Hashtable<Object, Object> p = to.getProperties(); String _class = p.get(".class").toString(); str.append("child::").append(_class); if (_class.contains("Html.TR")) { int rowIndex = this.getHtmlTRIndex(to); str.append("[").append(rowIndex + 1).append("]_@/@"); } else if (_class.contains("Html.TD")) { // 在IE的document模型中,所有的索引都是从1开始的 int index = this.getHtmlTDIndex(to); str.append("[").append(index + 1).append("]_@/@"); } else { int classIndex = this.getHtmlTOIndex(to); if (classIndex == -1) { if (_class.contains("Html.HtmlDocument") && p.containsKey(".title")) { String title = p.get(".title").toString(); str.append("[contains(@_").append(".title,'").append(title) .append("')]"); } str.append("_@/@"); } else { str.append("[").append(classIndex + 1).append("]").append( "_@/@"); } } }

    有了这个方法,我们就可以传入一个TestObject对象来获取到它的xpath。需要注意的是,通过脚本读取出来的TD、TR其classIndex是从0开始的,但是在IE和XPATH中所有元素的位置是从1开始的,这点切记

    public String getTestObjectTreeStr(TestObject to, String id, String value) {
    
    		if(to == null){
    			return "null";
    		}
    		
    		StringBuffer xpath = new StringBuffer();
    		addPropertyToCatch(to, id, value, xpath);
    		this.getTestObjectProperty(to, xpath);
    
    		String path = xpath.toString();
    		String rs = parseXpath(path);
    		return rs += "[1]";
    	}

    获取到对象的XPATH路径,我们就可以将对象路径字符串写入缓存文件,示意代码如下:

    public void writeXpathToFile(String ObjectID, String xpath, String filename) { File file = new File(filename); try { if (this.isObjectXpathExists(ObjectID, file)) { this.updataXpathbyObjectID(ObjectID, xpath, filename); } else { BufferedWriter writer = new BufferedWriter(new FileWriter(file, true)); writer.write(ObjectID + "=" + xpath); writer.write("\r\n"); writer.flush(); writer.close(); } } catch (IOException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } String rootStr = this.getFirstRootStr(xpath); String rootStr_ID = ObjectID + "_head"; try { if (this.isObjectXpathExists(rootStr_ID, file)) { return; } else { BufferedWriter writer = new BufferedWriter(new FileWriter(file, true)); writer.write(rootStr_ID + "=" + rootStr); writer.write("\r\n"); writer.flush(); writer.close(); } } catch (IOException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } file = null; }


    我们还需要考虑页面结构或者对象属性发生变化的情况,所以我们需要写一个方法实现自动更新缓存文件中的xpath路径。其实就是把更新后的XPATH路径读出去来,然后覆盖原来的路径

    public void updataXpathbyObjectID(String objectID,String xpath,String filename){
    ArrayList<String> list = new ArrayList<String>();
    StringBuffer sb = new StringBuffer();
    File file = new File(filename);
    BufferedReader in = null;
    BufferedWriter ut = null;
    try {
    in = new BufferedReader(new FileReader(file));
    String temp = "";
    while((temp = in.readLine()) != null){
    list.add(temp);
    }
    //查找并删除
    for(int i = 0; i < list.size(); i++){
    if(list.get(i).contains(objectID + "=")){
    sb.append(objectID + "=").append(xpath).append("\r\n");
    }else{
    sb.append(list.get(i)).append("\r\n");
    }
    }
    out = new BufferedWriter(new FileWriter(file));
    out.write(sb.toString());
    out.flush();
    out.close();
    out = null;
    in.close();
    in = null;
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }


    最后是使用缓存查找对象,这就 很简单了。不管你是用什么方法获得对象的,在调用你的代码之前,首先调用缓存对象的方法,实例代码如下:

    String xpath = this.getObjectCachePath(ObjectID, filename);
    to = GuiTestObjectFactory.getObjectByXPathAndWaitTime(rootGuiTestObject, xpath, 5);
    if(to == null){//如果根据缓存文件中的路径不能识别到对象,则转用find方法来执行以保证脚本的健壮性,这一步骤至关重要
    	RootTestObject root = this.getRootTestObject();
    	TestObject[] to = root.find(atDescant(".text","useName));
    	return to[0];
    }

    缓存对象路径的方法现在由我和我的同事在各自负责的自动化测试工程中分别使用,效果还算可以,自动化测试执行效率提高显著,以我的脚本为例,原来全部的脚本执行下来需要14个小时,使用这个方法后,执行时间缩短到了8个小时,只是执行的成功率有所下降,由原来的92%一度下降到75%……猜猜原因是什么?是因为脚本执行的太快了!原先find方法执行一次至少要几秒钟的时间,但是现在识别一个对象最快只要几百毫秒,所以很多健壮性的问题就暴露出来。现在我已经花了一个星期的时间不断的去完善,才有了现在87%的通过率(当然,还有部分是程序缺陷),所以如果您想开始用这个方法来完善自己的脚本,那么先做好心理准备吧,当然也要先和上级沟通好,不然一两个星期的人时砸进去但是他却看不到工作产出的,那可就……后面您懂的。

    到这里,我的方法基本就介绍完了,本文所说的方法只是一个优化方法之一,提高脚本的识别效率其实有很多方法可以采用,比如直接注入IE的进程获取到其document,然后用JS操作IE的元素,不骗您,这个方法真的可行,但是难度也确实有。有兴趣的同学可以试一下。本文中所列出的代码您拷过去是没法用的,因为有很多底层的代码没法贴,大家就参考代码了解思路吧,思路永远比代码重要。下一步我回把这部分代码写成一个JAR包发布出来,到时大家用起来就方便了。

    最后PS一下,千万别问我为什么不用FIREBUG插件直接获取XPATH路径……因为程序不支持FIREFOX,回答完毕。

  • 通过值守线程处理自动化测试的Runtime error错误提示框

    2012-06-16 10:29:04

        自动化测试开发过程中,脚本的健壮性是一个永远的话题,健壮性差的脚本会导致运行失败,影响我们最终的自动化测试效果。笔者在做自动化测试过程中,曾深受各种异常的困扰,在这里先分享一个Runtime Error C++错误提示框的处理,供大家参考。

        自动化测试的执行过程是无人值守的,所以对于执行过程中的异常处理就显得尤其重要。在我们碰到的各种异常中,IE浏览器抛出的Runtime Error c++的错误提示框无疑是最致命的,因为他会阻塞IE线程,导致RFT的执行线程挂起.对于web端的自动化测试来说,最令人沮丧的事情无非就是早上到公司后,看到屏幕上晃着一个大大的“Runtime error C++”提示框,这意味着自动化测试脚本的执行线程会被挂起,后面所有的脚本都不会得到执行。大家要注意一点,无论你在脚本做什么样的处理,对于这个提示框都无能为力,因为执行线程已经挂起了,你写的所有代码都无能为力。

        对于这个问题的处理其实也简单,那就是我们再写一个值守线程,当RFT的自动化测试启动运行时,值守线程同时启动,它每隔一定的时间就扫描当前屏幕上的测试对象,如果发现Runtime Error C++的错误提示框,就关闭它,这样可以保证后续的脚本能继续执行,当然,出现Runtime的脚本就作为异常放弃了。不过这个代价我们还是可以接收的。

        代码实现上,需要用到JAVA的Runable接口和RFT的IWindow接口,JAVA的Runnable接口实现值守线程,IWindow接口实现界面对象的扫描和查找。

    首先我们创建一个线程对象:

    public class DaemonThread extends Thread{}

    实现其run()方法

    public void run(){
            while(true){
                int count = 0;
                if(count > 30){
                    //每隔30秒扫描一次当前界面
                    findAndCloseRuntimeErrorDlg();
                    count = 0;
                }else{
                    //让出CPU资源
                    try {
                        Thread.sleep(1000);
                        count++;
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }

    findAndCloseRuntimeErrorDlg的实现

    public void closeRuntimeErorDlg(){
            IWindow[] wins = getTopWindows();
            for(int i = 0; i < wins.length; i++){
                String text = wins[i].getText();
                /*
                 * 如果在当前窗口中有Runtime Error C++,则执行关闭IE的操作
                 */
                if(text.contains("C++ Runtime Library ")){
                    try {
                        Runtime.getRuntime().exec("cmd /c taskkill iexplorer.exe");
                        Runtime.getRuntime().exec("cmd /c taskkill firefox.exe");
                        break;
                    } catch (IOException e) {
                        // TODO 自动生成 catch 块
                        e.printStackTrace();
                    }
                }
            }
            wins = null;
        }

    值守线程的启动:

    Thread t = new DaemonThread();
    t.start();

        实现以上代码后,我们把启动代码加到RFT的执行队列中,当脚本开始执行时,值守线程也随之启动,每隔30秒检查一下当前界面,如果界面中出现了Runtime Error C++提示框,则会关闭IE,以避免执行队列被挂起,从而保证了所有的测试脚本都能得到执行。



  • [论坛] 今天突然发现我把delphi的自动化测试想复杂了

    2009-06-16 22:46:32

       以前总对delphi的自动化测试有一种莫名的排斥感,理由很简单,我一直觉的很难获取到delphi的界面对象,因此潜意识里一直把delphi当成是自动化测试领域里的另类。但是今天看了ibm社区中的一篇文章,让我彻底改变了以前的想法。原来不是delphi的自动化测试难做,而是我把delphi的自动化测试象的太复杂了。以前总是认定rft对delphi是无法识别的,因此一直煞费苦心的想用IWindow接口构造出自己的对象识别机制。但是那篇文章点醒了我:delphi的自动化测试原来也可以如此简单。

       rft的强大不在于它象QTP那样提供了多少功能,而在于他的脚本和RFT提供的一系列接口,它给使用者带来了出乎意料的构造能力。这是QTP等测试工具所没有提供的。我觉的区别就在于他们使用的脚本不同。

    IBM那篇文章的地址我帖出来了,先不做过多说明,等以后有时间我再附文讨论。

    http://www.ibm.com/developerworks/cn/rational/r-cn-rftwindows2/index.html

  • [论坛] 在RFT下使用VSS插件

    2009-06-06 09:51:00

    一、介绍

          RFT的全程是Rational Functional Tester,是IBM的一款功能自动化测试工具,使用JAVA作为测试脚本。VSS大家已经都很熟悉了,一款使用相当广泛而且操作相当简单的版本控制工具。本身在Eclipse下使用vss插件不是什么难事,但是RFT下会有小小的不同,原因就是RFT的界面是被封装过的。虽然可以执行eclipse下的大部分操作,但是有些操作也是执行不了。这篇文章里对在RFT下使用vss插件做了一些小小的总结;

          如需转载,请注明出处:http://blog.csdn.net/wyp_810618,谢谢~!


    二、安装

         首先下载并安装RFT,过程忽略,因为这不是本文要讨论的内容;

         在本机上安装VSS,并连接到VSS服务器,过程忽略,理由同上;

         下在VSS插件,这里给出一个下载地址参考:http://downloads.sourceforge.net/vssplugin/org.vssplugin_1.6.2.zip,下载完成后,解压缩 zip 包放入 RFT plugin 文件夹,重启RFT(必须)。如果你的RFT使用的是默认目录,那么放到该目录下即可:C:\Program Files\IBM\SDP70\plugins。当重启RFT时可能会弹出一个错误,提示无法激活修饰符,该问题可以忽略,如果想避免出现这样的问题,那么就下载一个低版本的VSS插件即可

        这里要注意下,VSS插件与ECLIPSE的版本间是有兼容性的,只要使用的VSS插件能够支持Eclipse3.1或更高版本,那么就能在RFT中使用。低版本的VSS插件可能会出现无法预料的问题


    三、配置

        1. 首先配置vss的连接,点击RFT工具栏菜单“窗口——打开透视图——JAVA”,此时RFT的透视图切换到JAVA模式

        右键点选工程->Team->Share Project…;

      2. 选择VSS Configuration Wizard,点next;

      3. User Name和Password文本框中分别输入你的VSS用户名和密码;

      4.在确保自己的计算机可以在不输入密码的情况下登录到服务器上的情况下,直接输入或点Browse…选择VSSDatabase目录。最简单的方法是先通过访问共享的方式访问一下VSS服务器

        5. 设置完成后点击确定,即可完成VSS与服务端的连接。

    注意,此时我们还是在JAVA透视图下,需要将其切换到RFT的透视图下。方法同上;

        6. 在RFT工具栏菜单中添加VSS标签,方法是依此点击“窗口——定制透视图——命令”,在界面中勾选VSS Plugin menu and shortcut选项,确定,此时VSS标签出现在RFT菜单栏中,这主要是为了方便使用。


    四、使用

        1. check out:首先双击脚本进入脚本文件,然后点击VSS——refresh,然后点击check out按钮;或者直接在脚本中做改动,它会提示你是否进行check out,选择是即可;

        这里需要注意一个问题,有时你修改脚本时提示的不是是否check out,而是是否将脚本的只读状态更改为可写,此时不要更改,正确的做法应该是选择否,然后refresh一下,再修改时就会提示是否check out了。(应该是vss插件和RFT的兼容性问题)

        2. check in:双击脚本文件,然后点击VSS——check in即可,如果想要输入注释,那么首先启用。依此点击“窗口——首选项——小组——VSS”,选择Ask for common on add/check-in选项,然后确定即可;

        3. get laset version:这个操作稍微麻烦些,因为在RFT的项目上右键时并没有出现VSS的选项,我们需要切换到java透视图,然后执行get操作,再切换到RFT透视图

        4. add:选择脚本文件,然后点击VSS——ADD,即可将该脚本文件添加到VSS

        5. 比较版本差异:单击选择脚本文件,然后依此点击 VSS——Compare with lastest...,此时就能看到当前版本与上一版本间的内容差异了。


    基本的操作也就这么多了,以后有想到的话就再补充吧。

  • [论坛] 通过命令行启动RFT(Rational Functional Tester)

    2009-03-14 10:27:49

        使用命令行启动RFT的做法会有很多好处,对于我来说,首先它避免了我每次都要打开RFT的麻烦,而且使得脚本自动定时运行成为了可能.从命令行中启动RFT的方法在帮助文档中写的已经很清楚了,但是由于第一次操作,还是经过了一定的摸索阶段

        要从命令行启动RFT的话,首先要做的就是配置环境变量.假设我们的RFT安装目录为D:\Program Files\IBM;右击我的电脑--右键--属性--高级--环境变量.在环境变量中找到path,添加D:\Program Files\IBM\SDP70\jdk\bin;

        在RFT中新建一个RFT项目,保存目录为d:\src;在这个项目下新增一个测试脚本,里面写上:

        System.out.println("aaaa")

        在命令中编写代码如下,当然也可以写在记事本中然后粘贴过去

    java -classpath "D:\Program Files\IBM\SDP70\FunctionalTester\bin\rational_ft.jar;D:\Program Files\IBM\SDP70\FunctionalTester\bin\jxl.jar"  com.rational.test.ft.rational_ft -datastore "D:\src" -playback Script1

         然后在命令中回车,就可以看到RFT脚本被运行,并在CMD命令行中输出了aaaa

         在上面这段命令行中,第一个java没什么好说的,如果不明白那个java是什么意思的,这篇文章就可以忽略了;classpath指定了classpath的路径,有时我们在自动化测试框架中会引入第三方jar包,那么也把jar包的路径写进去,就象上面的D:\Program Files\IBM\SDP70\FunctionalTester\bin\jxl.jar;datastroe目录指定了你的项目目录,RFT根据它来定位脚本目录,playback表明动作是回放脚本,其他的还有record,complie,具体的用法可以参考帮助文档.Script1是脚本文件的名称,这个文件绝对不要带.java后缀名

         写Blog的目的就在于交流和分享,但是转载还是请注明出处http://blog.csdn.net/wyp_810618/archive/2009/03/14/3989478.aspx

    .谢谢

  • 论"自动化能做什么"

    2008-10-11 11:56:32

    最近在论坛、QQ群里,经常看到有人问:自动化测试能做什么,还有人曾经发消息给我,提出在需求阶段自动化测试能做什么这样的问题。本人并不觉的这样的问题有什么不妥,而且我相信很多人都在为这样的问题而困扰。我从事测试工作的时间也不是很长,做自动化测试也就一年多点的时间,在这里我就结合我的一些体会,和大家一起讨论一下自动化测试的一些问题吧,想到哪儿说到哪儿。欢迎大家交流,如要转载请注明出处:http://blog.csdn.net/wyp_810618。感激不尽

        首先讨论自动化测试能做什么这个问题,要回答它就需要提这个问题的人首先回答另一个问题,那就是你希望自动化测试做什么。自动化测试只是一种测试活动之一,和我们熟悉的功能测试、系统测试没什么区别。我们已经很习惯在功能测试、系统测试、性能测试等测试过程中去定义测试目标、安排测试计划、设计测试方案,自动化测试也一样啊,它也有测试目标、测试计划(脚本开发计划)、设计测试方案等活动。我从来没见过有人问系统测试能做什么,性能测试能做什么的问题,自动化测试也有它擅长的领域,自动化测试并不神秘,我想很多人真正迷惑的地方并不是自动化测试能做什么,他们真实困惑的是我希望自动化测试做什么

    扩展一下上面的那个我希望自动化测试做什么的问题,其实这个问题本身就是一个测试需求设计的问题。我希望大家能接受测试需求这个概念,不是只有客户才有需求,我们测试人员也有同样有测试需求,这个需求来源于我们希望改进测试过程、提高测试执行的效率和可靠性,扩大测试的覆盖率。其实功能测试、系统测试、性能测试等都会有测试需求,只是大家可能对这些需求太熟悉,所以反而都忽略了。测试需求就是我们的测试目标,自动化测试的需求就是我们的自动化测试目标,就是我们希望自动化测试做什么。举一个具体的例子,我们有一个软件,有一天测试人员甲反映了一个问题:在每次发版后,都需要验证数据保存的正确,但是这个功能已经开发N年了,比较稳定,可是不测试一遍又总觉的不放心,但是每次测试又耗费了大量的时间,还没有效果,时间长了就厌倦了。OK,我们看到自动化测试的需求已经提出来了,那就是发版后对数据保存功能的验证测试。我们希望能通过自动化测试的方式完成每次发版后的数据保存功能的测试,让测试人员甲可以把精力放在更需要人主观能动性的工作上,这也就回答了“我希望自动化测试能做什么”的问题。

    现在我们讨论第二个问题:自动化测试能做什么。当我们明确了自动化测试的目标后,并不是马上着急动手写脚本。为什么呢,因为在我们的工作中,提出自动化测试需求的人往往不是自动化测试工程师,而是手工测试人员。就象上面那个例子中的测试人员甲。测试需求提出后我们不能立刻去实现,而是要对测试需求进行分析,此时关注的重点就是需求的合理性。自动化测试不是阿拉丁神灯,它有人工测试无法比拟的优势,但是它也有自身的局限性。我们需要分析在提出的测试需求中,哪些需求是适合用自动化测试实现的。也许有人问,那到底什么样的需求才是适合用自动化测试实现的呢?对不起,这个问题小马我也无法回答,因为这个问题才宽泛了,要看需求是什么样,所采用的自动化测试框架是什么样的,还要看自动化测试工程师的代码能力。换句话,自动化测试能做什么,与所测试的软件、测试流程、测试人员的技能有很大的关系,当然,这些都取决于一个根本问题,那就是“自动化测试需求”

    讨论完这两个问题,我们再来讨论“需求阶段自动化测试能做什么”,对于这个问题,我还是刚才的观点,首先提问题的人你要回答“你希望在需求阶段自动化测试做什么”,这样回答并不是托词,大家想一想,如果我们还不能明确需求阶段我们要做什么工作,就算没有自动化测试,我们的工作也没法开展。所以对于这个问题,我希望大家能拆成几个小问题来回答:第一,需求阶段我们有哪些工作要做?第二、这些工作项中又有哪些是适合用自动化测试来做的?第三,我们用什么样的工具去实现。最后就是去实现它。

    说到实现,我们要讨论的第三个问题就来了,那就是如何做自动化测试。这个问题曾经也困扰过我很长时间,到现在很多人也在提这个问题。但是我觉的这个问题同样是一个无法回答的问题,为什么呢,因为这个问题也很宽泛,不是回答了你做完一二三四后,就实现自动化测试了。自动化测试本身也是一个开发过程,它涉及到需求分析、框架设计、脚本开发、运行维护等。如果真要回答如何做自动化测试这个问题,就要分别回答如何做自动化测试需求、如何设计自动化测试框架、如何进行开发测试脚本、如何运行维护等等,哪个问题讨论的话都能写本书出来。我曾经开过一个玩笑,如何自动化测试的问题等同于问如何让航天飞机上天,因为它们都包含了很多的子过程和方法论,而且答案不是唯一的。有人可能会说我故弄玄虚,因为现在很多测试工具都提供了脚本录制功能,自动化测试真的有那么难吗?对于这样的疑问,我也不想多做讨论,我只提出一个针锋相对的问题:使用自动化测试工具等于自动化测试吗?

    刚才讨论了三个问题,但是还有很多问题没有讨论。自动化测试是一个博大精深的领域,着实令人着迷。希望刚才小马的一些想法能对大家有所帮助,那样的话也不枉我打这么多字了,呵呵。

  • RFT中代码不能完全显示的解决方法

    2008-09-08 13:18:38

    这两天在用RFT时碰到了一个比较怪异的问题,当打开一个脚本文件或者进入某个类时,只能显示部分代码,给代码的查看和调试带来了很大的不方便。

        通过查找资料,知道这个问题的根本原因在于选择了RFT中的“仅显示所选元素的源”,如果是英文版的话,该功能的按钮名称叫“show source of selected element”。从Eclipse 3.2开始,该功能按钮被默认为隐藏不显示的。RFT很明显使用的是Eclipse3.2以后的版本作为扩展平台。想想以前可能是按哪个快捷键的时候,不 小心按错结果就糊里糊涂的启用这个功能了,而且半天找不到这个按钮在哪里,着实费了不少的力气。

        取消该功能的方法是,点击“窗口——定制透视图”,在该界面中点击“命令”页签,在命令列表中选择“编辑器表示”项,此时右侧的“工具栏详细信息”列表中就会出现“仅显示所选元素的源”功能项,点击一下将其取消即可。界面如图:

     

       

    如果是英文版的,则相应操作的按钮名称依此为:Windows---Customize Perspective----Commands,选择其中的 Editor Presentation项,点击Show source of selected element 将其取消即可。

  • RFT测试对象检查器与jdk版本的兼容性问题

    2008-07-09 09:30:58

    一、问题 我所使用的RFT是v7.0.1.2版本,一切正常。但是当我把JDK从1.4.2更新成1.6以后,测试对象检查器就出现了问题。具体表现是,当对象检 查器悬浮在IE界面上时,无论用鼠标点击那里,都无法识别出IE的任何属性。而对于RFT自带的演示程序,对象检查器可以正确的识别。
     二、分析 对比问题出现前后的工作环境,我将问题定位在了JDK上。IE使用默认的java插件,其版本与机器上所安装的JDK版本一致。可能RFT的对象检查器在 识别IE时,与IE的JAVA插件有依赖关系。RFT中的JDK是1.5版本,而我的JDK是1.6,这样有可能出现不兼容的情况(仅为个人推测)。恰巧 这时部门里一个漂亮的女同事也将JDK升级为1.6,在她的机器上,也出现了测试对象检查器不能识别IE对象的问题。
     三、解决 问题定位后就开始着手解决,首先我修改环境变量,将jdk1.6全部替换成1.4.2,重启机器,问题依旧;
     在IE的(工具——选项——程序——管理加载项)中,禁用JDK1.6插件,重启IE,问题依旧;
     同样在IE的(工具——选项——程序——管理加载项)中,点击JDK1.4.2,点击更新activeX插件,更新失败,放弃;
     在控制面板中,卸载jdk16和1.4.2,清除系统变量中所有关于JAVA的配置,然后重新安装JDK1.4.2并配置JAVA环境变量,问题依旧;
     在我的RFT中我曾经装过VSS插件,于是将VSS插件禁用,重启RFT,问题依旧,再重启机器,问题依旧;
     实在无奈,抱着机箱大喊:”我爱你“,问题依旧。 重装RFT,并升级为7.0.1.2,问题解决
    四、花絮
    今天早上,漂亮的女同事给我发消息,说这个问题不用重装也可以解决,方法是在RFT的“窗口—首选项”中,点击“JAVA—已安装的JRE”,将JDK1.6 添加进来;然后在“ECLPSE配置—启用环境进行测试“中,点击JAVA页签,将JDK1.6添加进来,最后将原来缺省的禁用。然后重启RFT就OK了, 前后不用五分钟的时间。
    想想一开始的时候我那么胡乱折腾,真是好笑。到底还是对RFT的相关功能不熟悉。
  • RFT不能安装RDT问题的处理

    2008-07-08 09:37:57

    RDT是ruby在eclipse上的插件,同样可以使用在rational functional tester中。但是RDT却对rft的版本有要求。如果安装的是rft 7.0.0.1,则不能安装RDT插件,表现就是看不到任何的ruby透视图,在帮助——查找并更新中虽然能看到ruby的节点,但是在网络畅通的情况下 却总是提示更新失败。
     要安装RDT插件,首先需要更新IM版本,如果是从7.0.0.1更新,则首先打开管理平台Installation Manager,他应该会提示有一个v1.1的更新,首先更新IM,如果没有该提示的话,则说明你的IM已经是最新版本。
    IM更新后,需要更新RFT版本,打开im,点击“更新软件包”,然后一直下一步即可完成更新。 截止到我发表这篇文章(2008-7-8)为止,RFT的更新版本是7.0.1.2,更新完成后,复制RDT的features和plugins文件夹到 rft安装目录下的sdp70目录,覆盖同名文件夹。然后启动RFT,在“窗口—选项”界面右侧的列表中,即可看到RUBY节点。相关配置在这里就不说 了,百度里一搜一堆,我另一篇文章也有写。
  • RFT无法识别windows对话框的处理方法

    2008-07-02 22:36:20

    一、概述

    RFT中提供了find方法,这是一个很强大的工具,可以让我们在脱离测试对象的情况下运行测试脚本,这样我们的脚本就有了很好的健壮性和可移植性(在去年的自动化测试项目中,QTP就经常因为测试对象的属性问题导致脚本运行失败)。但是今天在利用测试对象检查器获取windows对话框属性时,碰到了一个很极端的问题,对象检查器竟然无法识别windows对话框。最后几经周折,终于解决了这个问题

    二、问题

    脚本的操作过程是这样的,首先点击界面中的导出按钮,这时系统会弹出一个是否保存的确认提示框,这时点击“是”,然后系统会在该对话框的基础上打开一个新的文件保存对话框。这时我发现用测试对象检查器根本无法获取到该对象的任何属性,用find方法查找时也找不到任何的对象。使用的属性是“.name”,属性值是"另存为"

    三、分析

    该问题的根本原因在于RFT的对象识别机制。通过查阅资料和api,我觉的RFT所能处理的对象关系可以分为两种,一种是父子关系的对象集合,另一种我们暂且叫做顶层——下层关系的对象集合。举个简单的例子,一个拥有“确定”“取消”两个按钮的确认提示框就是父子关系的对象,确认提示框是父对象,确定按钮和取消按钮就是这个按钮的子对象。父子类型的对象可以很容易的被对象检查器或find方法找到;顶层——下层关系的对象就象我们上面举的那个例子:在已经存在的windows对话框的基础上,又出现了一个对话框。两个对话框并非是父子关系,而是一种嵌套关系,并且很明显,其中有一个对话框是顶层窗口,也就是焦点的拥有者,在开发上也有叫做模态窗口的。顶层——下层对象不能被对象检查器所识别。当然,这些都是我目前对rft的理解,IBM的网站并没见过类似的解释。利用GuiTestObject我们可以很方便的处理父子关系的对象,但是对于顶层——下层关系的对象,GuiTestObject对象则无能为力(至少在我这里是这样)

    四、解决

    要解决该问题不妨换一个角度,RFT提供了访问window平台控件的接口,那就是IWindow。既然我们不能通过TestObject类获取保存对话框的属性,那么我们就把保存对话框当成是一个windows对象,用IWindow来识别。我们需要解决以下问题:

    1、首先让脚本获取到文件保存对话框对象,该对象的类型是IWindow,对象获取可以使用getText返回的属性,文件保存对话框的getText会返回“另存为”。

    2、调用IWindow的inputChars录入文件保存的目录。

    3、让脚本获取到该保存对话框对象的子对象“保存”按钮,并执行点击操作

    为了实现以上的功能,我们需要两个方法,分别是getTopWindow和getLevelWindow,在IBM网站上有篇相关的文章,链接请见第五节,这里直接贴出代码:

    1. /**  
    2.      * 返回window系统中顶层窗口的对象,例如getTopWindow("另存为")将返回一个windows另存为对话框,与getLevelWindow不同的是,Topwindow对象可以执行inputChars方法,而LevelWindow则不行.  
    3.      * @param objName windows窗体、对话框、元素的getText属性  
    4.      * @return IWindow windows控件(对象),该对象是顶层窗口  
    5.      */  
    6.   
    7.     public IWindow getTopWindow(String objName) {   
    8.   
    9.   
    10.   
    11.         IWindow[] wins = RationalTestscrīpt.getTopWindows();   
    12.   
    13.         int length = wins.length;   
    14.   
    15.         for (int i = 0; i < length; i++) {   
    16.   
    17.   
    18.   
    19.             if (wins[i].getText().matches(objName)) {   
    20.   
    21.                 return wins[i];   
    22.   
    23.             }   
    24.   
    25.         }   
    26.   
    27.         return null;   
    28.   
    29.     }  
    1. <PRE class=java name="code">/**  
    2.      * 对于某些二级弹出窗口,可用该方法进行识别和操作,该方法返回指定名称的对象,例如getWinObject("另存为","保存(&S)"),该方法回返回windows保存对话框中的"保存"按钮.  
    3.      *   
    4.      * @param topWinName  
    5.      *            顶层窗口对象的getText属性  
    6.      * @param levelWinName  
    7.      *            顶层对象下子对象的getText属性  
    8.      * @return IWindow对象,该对象可执行单击和双击的操作.  
    9.      */  
    10.   
    11.     public IWindow getLevelWindow(String topWinName, String levelWinName) {   
    12.   
    13.         IWindow winobjects = null;   
    14.   
    15.         IWindow[] wins = RationalTestscrīpt.getTopWindows();// 返回windows对象数组   
    16.   
    17.         for (int i = 0; i < wins.length; i++) {// 在数组中查找所有符合topWinName属性的对象   
    18.   
    19.             if (wins[i].getText().equals(topWinName)) {   
    20.   
    21.                 winobjects = wins[i];   
    22.   
    23.             }   
    24.   
    25.         }   
    26.   
    27.         IWindow[] winobj = winobjects.getChildren();   
    28.   
    29.         for (int i = 0; i < winobj.length; i++) {   
    30.   
    31.             if (winobj[i].getText().equals(levelWinName)) {// 在顶层对象中,查找符合levelName属性的对象   
    32.   
    33.                 return winobj[i];   
    34.   
    35.             }   
    36.   
    37.         }   
    38.   
    39.         return null;   
    40.   
    41.     }</PRE>   
    42. <PRE class=java name="code">最后实现文件保存框识别和文件保存的代码如下:</PRE>   
    43. <PRE class=java name="code">test.getLevelWindow("另存为""文件名(&N):").click();//点击文件保存文本框,获取焦点.   
    44.   
    45. test.getTopWindow("另存为").inputChars("c:\\result.xls");//录入保存文件的对话框</PRE>  

    五、小结

     

    当代码完成后,我发现这个问题其实并不复杂,所有的类和方法rft都已经提供了,只是由于以前我不熟悉IWindow的用法,所以走了不少的弯路,直到看到ibm网站上的一篇文章才豁然开朗。其实不仅仅是保存对话框,任何windows平台的控件,我们都可以用IWindow来实现查找和定位。  

     

     

    http://www.ibm.com/developerworks/cn/rational/r-cn-extendsrftobj/index.html

  • 在Rational Function Tester中使用JRuby

    2008-06-29 10:17:12

    一、概述

    Rational Function Tester是IBM的一款功能自动化测试工具,使用JAVA作为脚本语言,不了解他的朋友可以去IBM网站看看。

    RUBY是目前WEB开发中炙手可热的语言,简单,灵活,宽松,并且有趣。在公司今年的自动化测试项目中使用了RFT搭建测试框架,同时对于页面中一些OCX控件的识别采用RUBY进行识别。这样的话就需要解决JAVA代码与RUBY脚本之间变量传递和方法调用的问题,JRUBY自然成了最好的选择。

    这篇文章里我把自己配置和实验的过程帖出来,与大家分享和交流

    二、准备

    需要安装的运行环境有:JRuby,RFT,JAVA SE 6.0。

    Jruby和jdk 1.6的安装在我的另一篇文章已经介绍了,大家可以访问以下地址查看:

     http://blog.csdn.net/wyp_810618/archive/2008/06/28/2595180.aspx

    RFT的安装请参考IBM网站的说明

    为了能在RFT中使用Ruby,我们还需要下载RDT插件,有人可能会奇怪,这不是Eclipse中的插件吗?没错,因为RFT本身就是一款基于Eclipse平台的测试工具(现在我更喜欢把RFT软件叫成“Eclipse的RFT插件”)

    RDT下载地址:http://jaist.dl.sourceforge.net/sourceforge/rubyeclipse/org.rubypeople.rdt-0.7.0.601192300PRD.zip

    三、RFT配置

    1、将RDT压缩包解压到任意目录,得到features和plugins两个目录,将这两目录拷贝到RFT的安装目录D:\program files\IBM\SDP70目录下,覆盖原目录。

    2、启动RFT,依此点击:窗口——首选项,在左侧列表中应该能看到Ruby节点,然后依此点击Ruby——Installed Interpreters节点

    3、在该界面中配置Jruby的运行环境。点击Add按钮,在新建窗口中,Interpreters Name可自定义,Location中填入%JRUBY_HOME%/bin/jruby.bat目录,其中%JRUBY_HOME%是你jruby的安装目录,可以在环境变量中查看。录入完成后应该类似于这个样子 :

    点击确定后即可完成配置

    四、验证

    安装完成后,我们需要验证jruby是否能在RFT下正常运行。

    首先在RFT中新建一个Ruby项目,在项目列表中能看到Ruby节点,不知道怎么操作的朋友自己去百度上搜一下eclipse的用法吧;

    在RFT中新建Ruby项目后,需要切换透视图才能看到项目节点,点击窗口——打开透视图——其他,在列表中选择Ruby节点,点击确定,此时在RFT左侧的项目中就能看到刚才新增的RUBY项目

    在RUBY项目节点上右键,新增一个文件,文件名为HelloWorld.rb(注意,一定要带.rb后缀名),然后在该文件中录入如下代码:

    puts "Hello JRuby world"

    以上代码末尾无任何符号。保存。

    最后,在该文件上点击右键——运行方式——Ruby application,运行该文件。如果能看到控制台中输出Hello JRuby world,则说明该配置已经生效。

    如果在控制台中出现报错信息:'cmd'不是内部命令也不是外部命令,那么请修改%JRUBY_HOME%/bin/jruby.bat文件,将最后一行代码注释掉即可。

  • RFT自动化测试中的相对路径

    2008-06-17 18:52:15

    相对路径的问题不是RFT自动化测试中独有的,所有涉及到团队开发的代码都必须解决相对路径的问题。解决方法也是多种多样,对于j2ee的程序来说,中间件提供了上下文环境,也有把根目录写在环境变量或配置文件里的。昨天在论坛上看到了RFT提供的getOption方法,感觉用它来实现脚本的相对路径和迁移十分方便。
    假设我们RFT自动化测试的项目路径为d:\ci_automation\src,然后在src下面我们有\data,\scrīpt,\lib,\common……文件夹,那么我们写这样的代码:
    String s = (String)getOption(IOptionName.DATASTORE);
    System.out.println(s)
    其中getOption方法是Rft提供的静态方法,可以直接调用;IOptionName是Rft提供的一个接口,具体作用目前不详,该接口有一个类成员变量static String DATASTORE,储存着RFt项目的目录;上面代码的作用就是返回Rft项目的目录,运行的结果是d:\ci_automation\src
    当我们需要引用\common文件夹时,我们可以这样写:
    String file = s + "\\common\\test.xls"//在java下目录的分隔符需要用\\
    用这样的方法,我们甚至连环境变量都省了。当然用这个方法也是有条件的,那就是测试机上必须安装Rft软件

  • 在RFT中实现文本框录入

    2008-06-16 19:05:23

    在RFT中,要对ie的文本框执行录入操作稍微有点怪异。在QTP中,获取到文本框对象后,执行object.set方法,就可以实现数据的录入,但是在RFT中不行。在RFT中,对文本框的数据录入要通过setproperty来实现。例如在我的测试过程中,RFT获取到用户名录入框有一个属性.value,录入用户名时要执行object.setproperty(".value","admin");其中,object就是我获取到的文本框对象,本来有一个setText(String s)方法的,但是我用find方法返回的是GuiTestObject对象,没有setText方法,所以只能使用setprpoerty方法了这也算是今天一个小小的收获吧。
  • 关于RFT中使用DEBUG提示“无法创建 Java 虚拟机”的处理

    2008-05-18 15:44:14

    1. 问题描述

    在RFT 7.0中,当点击DEBUG按钮时会导致RFT控制台报错,错误信息如下:

    JVMJ9TI002E Agent_OnLoad not found in library jdwp
    JVMJ9VM015W Initialization error for library j9jvmti23(-3): JVMJ9VM009E J9VMDllMain failed
    无法创建 Java 虚拟机。

    随后RFT提示无法弹出信息提示框,大意是建议恢复JAVA的构建路径,无法连接到VM

    1. 问题解决

    对于该问题,百度和GOOGLE上的中文资料非常少,而且大多文不对题,经过多方查找,最后在IBM社区中找到了解决方法,只不过是英文的,该问题的根本原因还是RFT的JDK与其他JDK冲突。在我的机器上是由于ORACLE的JDK与RFT的JDK冲突导致的。解决方法如下:

    进入C:\Program Files\Oracle\jre\1.3.1\bin\目录,该目录下会有一个jdwp.dll文件,将该文件删除或者改名即可。修改完毕后再次进入RFT后,DEBUG功能就可以正常使用了。

    需要注意的是,C:\Program Files\Oracle\jre\1.3.1\bin\并非是ORACLE的安装目录,例如我本机上ORACLE的安装目录是D盘,那么我们要修改的不是D盘的文件,是XP系统program files下的oracle目录,切记。

    在使用RFT的过程中可能会遇到很多报错的情况。如果是与虚拟机相关的,那么可以先检查一下是否存在JDK冲突。

    1. 其他

    将jdwp.dll修改或删除后不会对ORACLE数据库的使用造成任何影响。网络上有关与jdwp.dll文件的介绍并不是很多,我只是知道JDWP 定义了JVM与调试客户端之间的通讯协议,从这里判断ORACLE的jdwp.dll文件也是和debug功能相关的。

    IBM RFT使用自带的JDK,我查了一下该JDK的版本,发现竟然是1.5的。但是该JDK下的jar包和类库与SUN的JDK完全不一致。我将myeclipse中的JDK换成RFT的JDK 后,也可以在myeclipse中编辑RFT的脚本,并调用TestObject类的方法,但是却不能在MYECLIPSE中运行RFT的脚本。

  • 关于RFT中顺序读取数据表

    2008-05-14 16:47:04

    这两天一直在学习RFT工具,碰到的第一难题竟然是对数据表进行遍历。
    例如我有一张数据表,里面只有一个字段:usr_name,储存用户登录名。里面有十行记录。现在我要做的就是把这十行记录都输出,在实际的项目过程中,我们会要求输入这十个用户名。
    第一次实验时发现测试脚本运行完第一行后就结束了,而且我竟然没找到数据表读取设置的选项(刚学习,实在找不到)。由于不熟悉RFT的功能和语法,在花费了近三个小时充分研究了datapoolscrīptsupport和Idatapool及相关的方法后,终于将代码写出来了,代码如下:
    while(!dpDone()){
          System.out.println(dpString("usr_name"));
          this.dpNext();
    }
    写完后我就哭了,三个小时四行代码!
    不过这个跟头栽的不冤,通过研究这个问题,我弄明白了以下几个问题:
    1、RFT软件中一个脚本只能关联一个测试数据表,虽然可以通过自自己定义JAVA接口实现对多个数据表的读取,但是那不是RFT软件的功能;
    2、正因为RFT中一个脚本只关联一个测试数据表,所以在脚本中我们可以直接使用DatapoolscrīptSupport对象的dpString()方法来获取参数值。其实我很想知道这个dpString()方法是怎么实现的,为什么我不用创建DatapoolScripsuppor对象的实例就可以直接调用该方法?,但是翻遍了API文档也没找到,只好暂时作罢。
    3、如果仅仅是读取与脚本关联的测试数据表,我们用不到datapoolscrīptsupport和Idatapool这两个类。
    4、RFT对数据驱动的理解与QTP不同,这点从数据表就能看出来,QTP中每一个脚本都有两种数据表,分别是全局表和本地表,并且在一个脚本中我们可以增加无限个本地表,也就是说,QTP脚本与测试数据表是一对多的关系;但是RFT中,脚本与测试数据表就是一对多的关系,也就是说一个数据池可以被多个脚本所共享。这点差别会导致自动化测试设计的差异。具体会有哪些差异我一时也举不出例子来。
    5、通过三个小时的反复折腾,我对RFT的API文档结构更加熟悉了。在以后的脚本开发过程中,这将大大提高我的开发效率。
    6、RFT中脚本与数据表多对一的关系会使设计和开发过程更简单。
Open Toolbar