2009年4月20日

                  找到對(duì)象之后,就需要對(duì)其進(jìn)行操作了。在對(duì)對(duì)象進(jìn)行操作之前,需要了解RFT處理對(duì)象的方式。根據(jù)RFT的文檔,Java對(duì)象的關(guān)系如下圖:


                  由此可見,絕大多數(shù)的對(duì)象都是繼承于GuiTestObjectGuiSubitemTestObject。類似ButtonCheckBox這樣的簡(jiǎn)單對(duì)象,自然是繼承于GuiTestObject,而像ListTable這樣的有內(nèi)部子對(duì)象的復(fù)雜對(duì)象,一定是繼承于GuiSubitemTestObject。根據(jù)這一規(guī)律,就可以分別建立你所需要的類了。

                  負(fù)責(zé)Button的類如下:

          package framework.widgets;

          import java.awt.Point;

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;

          import com.rational.test.ft.object.interfaces.GuiTestObject;
          import com.rational.test.ft.object.interfaces.TestObject;

          public class WButton extends GuiTestObject {
              
              
          public WButton(TestObject button) {
                  
          super(button);
              }
              
              
          public void click() {
                  
          super.click();
              }
              
              
          public void click(int x, int y) {
                  
          super.click(new Point(x, y));
              }
              
              
          public void doubleClick() {
                  
          super.doubleClick();
              }
              
              
          public boolean isEnabled() {
                  
          return super.isEnabled();
              }
          }

              其他簡(jiǎn)單對(duì)象也可以繼承ToggleGUITestObjectTextScrollTestObject等其他衍生于GuiTestObject類,這些類封裝了很多實(shí)用的方法可以直接使用,具體請(qǐng)參考RFT文檔中的API

              負(fù)責(zé)TabPane的類如下:

          package framework.widgets;

          import java.util.Vector;

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;

          import com.rational.test.ft.object.interfaces.GuiSubitemTestObject;
          import com.rational.test.ft.object.interfaces.TestObject;
          import com.rational.test.ft.script.Index;
          import com.rational.test.ft.script.Text;
          import com.rational.test.ft.vp.ITestData;
          import com.rational.test.ft.vp.ITestDataElementList;
          import com.rational.test.ft.vp.ITestDataList;

          public class WTabbedPane extends GuiSubitemTestObject {

              
          static final Logger logger = LoggerFactory.getLogger("WTabbedPane.class");
              
              
          public WTabbedPane(TestObject tabbedPane) {
                  
          super(tabbedPane);
              }
              
              
          public void clickTab(String tabName) {
                  
          this.click(new Text(tabName));
              }
              
              
          public void clickTab(int index) {
                  
          this.click(new Index(index));
              }
              
              
          public int getTabCount() {
                  logger.info(
          "Get tab count");
                  ITestData data 
          = (ITestData) super.getTestData("list");
                  ITestDataList list 
          = (ITestDataList) data;
                  
          return list.getElementCount();
              }

              
          public int findTab(String text) {
                  logger.info(
          "Find the index of tab {}", text);
                  Vector contents 
          = this.getAllTabs();
                  
          for (int i = 0; i < contents.size(); i++) {
                      
          if (contents.get(i).toString().equals(text)) {
                          
          return i;
                      }
                  }
                  
          return -1;
              }

              
          public String getTabText(int index) {
                  logger.info(
          "Get tab text with index {}", index);
                  Vector contents 
          = this.getAllTabs();
                  
          if (index < 0 || index >= contents.size()) {
                      
          return null;
                  }
                  
          return (String) contents.get(index);
              }
              
              
          public Vector getAllTabs() {
                  logger.info(
          "Get all tabs");
                  ITestDataList dataList 
          = (ITestDataList) super.getTestData("list");
                  ITestDataElementList elementList 
          = (ITestDataElementList) dataList
                          .getElements();
                  
          return elementList.getElements();
              }
          }

              由上面的例子可以看出來,對(duì)對(duì)象的操作可以分為兩類:一類是施加行為,一類是讀取數(shù)據(jù)。對(duì)此,RFT的API給出了詳細(xì)的文檔,例如對(duì)于List對(duì)象,文檔如下:

              由此可看出,對(duì)于List對(duì)象,可以通過.class, .classIndex, .itemCount, .itemText, .priorLabel,accessibleContext.accessibleName,name和toolTipText這些屬性進(jìn)行識(shí)別。獲取List對(duì)象后,它支持Text和Index這兩類子對(duì)象,可通過ITestDataList接口獲得全部列表元素和已選列表元素。上面getAllTabs()方法就是用來獲得所有Tab選項(xiàng)的,可以作為參考。

              還有一些更為復(fù)雜的簡(jiǎn)單對(duì)象,如:TextField和Frame,以及復(fù)雜對(duì)象,如:Table和Tree。如果你能夠理解上述處理對(duì)象的方法,那么完全可以編寫符合自己項(xiàng)目需要的方法,對(duì)這些對(duì)象進(jìn)行各種各樣的操作。



          posted @ 2009-04-20 16:44 terrypang 閱讀(1453) | 評(píng)論 (2)編輯 收藏

          2009年3月31日

          如何靈活查找窗體內(nèi)的對(duì)象呢?和查找窗體類似,可以使用這些對(duì)象特有的屬性,依照一定的查找邏輯進(jìn)行處理。下面是一個(gè)典型的查找方法,以此為例進(jìn)行說明:

              public TestObject getObject(ArrayList<Property> v) {

                  rootTO.waitForExistence(waitMaxTime, waitCheckInterval);
                  TestObject returnObject 
          = null;
                  TestObject to[] 
          = null;
                  
          double timeNow = System.currentTimeMillis() / 1000;
                  
          double endTime = timeNow + waitMaxTime;
                  v.add(
          new Property("showing""true"));
                  
          while (returnObject == null && timeNow < endTime) {
                      to 
          = rootTO.find(atDescendant((Property[]) v.toArray(new Property[0])));
                      
          if (to.length > 1{
                          
           throw new AmbiguousRecognitionException("Find more than one object.");
                      }

                      
          if (to.length == 1{
                          returnObject 
          = to[0];
                      }
           else
                          sleep(waitCheckInterval);
                      timeNow 
          = System.currentTimeMillis() / 1000;
                  }

                  
          return returnObject;
              }

          上面的方法根據(jù)傳入的參數(shù)集合對(duì)當(dāng)前窗口中的所有對(duì)象進(jìn)行查找。和之前的窗體查找一樣,最好顯示的添加showing=true參數(shù),因?yàn)樵?/span>Swing程序的運(yùn)行過程中,內(nèi)存中會(huì)對(duì)GUI元素進(jìn)行緩存,可能一個(gè)界面消失了,但它還在內(nèi)存中,等待著隨后被顯示。這樣一來,就需要這個(gè)參數(shù)過濾到所有未被顯示的GUI元素。在實(shí)際使用過程中,可以使用如下的方法進(jìn)行調(diào)用: (調(diào)用前使用RFT的對(duì)象查看器確定待查找對(duì)象的唯一屬性)

          protected WButton getButton(String name) {
                  ArrayList
          <Property> v = new ArrayList<Property>();
                  v.add(
          new Property(".class""javax.swing.JButton"));
                  v.add(
          new Property("accessibleContext.accessibleName", name));
                  TestObject to 
          = og.getObject(v);
                  
          if (!Utility.exists(to))
                      
          throw new ObjectNotFoundException();
                  
          else
                      
          return new WButton(to);
              }
           

          與窗口處理一樣,如果某些參數(shù)需要使用正則表達(dá)式處理,可以使用下面的方法:

              protected WListBox getList(String label) {
                  RegularExpression exp 
          = new RegularExpression(".*JComboBox$|.*JList$"false);
                  ArrayList
          <Property> v = new ArrayList<Property>();
                  v.add(
          new Property(".class", exp));
                  v.add(
          new Property(".priorLabel", label));
                  TestObject to 
          = og.getObject(v);
                  
          if (!Utility.exists(to))
                      
          throw new ObjectNotFoundException();
                  
          else
                      
          return new WListBox(to);
              }
           

          在對(duì)象查找過程中,可能需要各種不同的查找邏輯。例如,如果對(duì)象可能存在也可能不存在,在查找的時(shí)候就不需要等待并反復(fù)查找,這時(shí)候,可以使用如下的方法:

              public TestObject getObjectWithoutWait(ArrayList<Property> v) {
                  rootTO.waitForExistence();
                  TestObject returnObject 
          = null;
                  v.add(
          new Property("showing""true"));
                  TestObject to[] 
          = rootTO.find(atDescendant((Property[]) v.toArray(new Property[0])));
                  
          if (to.length > 1{
                      
          throw new AmbiguousRecognitionException(
                              Find more than one object.);
                  }

                  
          if (to.length == 1{
                      returnObject 
          = to[0];
                  }

                  
          return returnObject;
              }

           

          有時(shí)候,界面上有多個(gè)具有相同屬性的對(duì)象,只能通過他們的編號(hào)來區(qū)分他們;有時(shí)候需要以某個(gè)確定對(duì)象為根來進(jìn)行查找;有時(shí)候需要查找直接子對(duì)象而不是所有子對(duì)象,等等。并且,這些邏輯之間也存在排列組合的情況,實(shí)際使用中可以根據(jù)自身需要靈活處理。這些方法都是對(duì)上面基本方法的擴(kuò)展,大家可以嘗試自己來實(shí)現(xiàn)。

          posted @ 2009-03-31 09:31 terrypang 閱讀(1189) | 評(píng)論 (0)編輯 收藏

          2009年3月21日

           

          窗體是程序的基礎(chǔ)。無論是主窗體,還是彈出窗體,他們往往都是需要首先定位的對(duì)象。窗體,作為一類特殊對(duì)象,他們都是根對(duì)象的直接子對(duì)象,針對(duì)這一特點(diǎn),對(duì)他們定位就非常簡(jiǎn)單了。通常,通過窗體標(biāo)題,就能很好的找到所需的窗體。具體方法如下。

          private double waitCheckInterval = ((Double) getOption(IOptionName.WAIT_FOR_EXISTENCE_DELAY_BETWEEN_RETRIES))   
                  .doubleValue();    
          private double waitMaxTime = ((Double) getOption(IOptionName.MAXIMUM_WAIT_FOR_EXISTENCE))   
                  .doubleValue();    
          private TestObject rootTO = null;   
          public boolean getRootWithCaption(String captionExpr) {   
              
          double timeNow = System.currentTimeMillis() / 1000;   
              
          double endTime = timeNow + waitMaxTime;   
              rootTO 
          = null;   
              
          while (rootTO == null && timeNow < endTime) {   
                  RootTestObject root 
          = RootTestObject.getRootTestObject();   
                  TestObject[] ftWinObjects 
          = null;   
                  RegularExpression exp 
          = new RegularExpression(captionExpr, false);   
                  ArrayList
          <Property> v = new ArrayList<Property>();   
                  v.add(
          new Property(".captionText", exp));   
                  v.add(
          new Property(".domain""Java"));   
                  v.add(
          new Property("showing""true"));   
                  ftWinObjects 
          = root.find(atChild((Property[]) v.toArray(new Property[0])));   
                  
          if (ftWinObjects != null{   
                      
          if (ftWinObjects.length > 1{   
                          
          throw new AmbiguousRecognitionException("Find more windows with capture: " + captionExpr);   
                      }
             
                      
          if (ftWinObjects.length == 1{   
                          rootTO 
          = ftWinObjects[0];   
                          
          return true;   
                      }
             
                  }
           else {   
                      sleep(waitCheckInterval);   
                      timeNow 
          = System.currentTimeMillis() / 1000;   
                  }
             
              }
             
              
          return false;   
          }
            
           

          上面的方法首先取得對(duì)象查找的間隔時(shí)間、最大等待時(shí)間,并聲明了空的窗體對(duì)象。接下來進(jìn)入方法,根據(jù)查找結(jié)果和最大等待時(shí)間來循環(huán)查找窗體。先獲得根測(cè)試對(duì)象,然后查找其直接子對(duì)象,查找條件為:窗體標(biāo)題符合正則表達(dá)式captionExpr的定義,屬于Java域,并且當(dāng)前為顯示狀態(tài)。最后處理查找結(jié)果,如果結(jié)果大于1個(gè),則拋出異常;如果結(jié)果等于1,則返回true;如果結(jié)果為空,則等待并重新計(jì)算時(shí)間,并繼續(xù)循環(huán)查找;如果最后仍未空并退出循環(huán),則返回false

          有的時(shí)候,窗口的出現(xiàn)并不是一定的,例如很多彈出窗口。這時(shí)候,對(duì)象查找并不需要循環(huán)等待,相應(yīng)的方法應(yīng)為:

          public boolean getRootWithCaptionWithoutWait(String captionExpr) {   
              rootTO 
          = null;   
              sleep(waitCheckInterval);   
              RootTestObject root 
          = RootTestObject.getRootTestObject();   
              TestObject[] ftWinObjects 
          = null;   
              RegularExpression exp 
          = new RegularExpression(captionExpr + "$"false);   
              ArrayList
          <Property> v = new ArrayList<Property>();   
              v.add(
          new Property(".captionText", exp));   
              v.add(
          new Property(".domain""Java"));   
              v.add(
          new Property("showing""true"));   
              ftWinObjects 
          = root.find(atChild((Property[]) v.toArray(new Property[0])));   
              
          if (ftWinObjects != null{   
                  
          if (ftWinObjects.length > 1{   
                      
          throw new AmbiguousRecognitionException("Find more windows with capture: " + captionExpr);   
                  }
             
                  
          if (ftWinObjects.length == 1{   
                      rootTO 
          = ftWinObjects[0];   
                      
          return true;   
                  }
             
              }
             
              
          return false;   
          }
            
           

          這樣一來,就可以用統(tǒng)一的方法來進(jìn)行窗體的查找。具體代碼如下:

          protected boolean ExistWin(String winName, boolean wait) {   
              release();   
              
          if (wait)   
                  
          return og.getRootWithCaption(winName);   
              
          else  
                  
          return og.getRootWithCaptionWithoutWait(winName);   
          }
             
            
          public boolean isDialog(String caption, boolean wait) {   
              
          return super.ExistWin(caption, wait);   
          }
            
           

          前一個(gè)方法利用傳入的窗體標(biāo)題正則表達(dá)式,和窗體查找邏輯,進(jìn)行窗體查找。后一個(gè)方法對(duì)其進(jìn)行調(diào)用,返回是否查找成功的結(jié)果。事實(shí)上,這兩個(gè)方法完全可以寫成一個(gè),但是在設(shè)計(jì)框架時(shí),應(yīng)考慮到自動(dòng)化操作的各個(gè)環(huán)節(jié),應(yīng)把每一個(gè)環(huán)節(jié)獨(dú)立開來,才能具有最大的靈活性。根據(jù)我的經(jīng)驗(yàn),對(duì)對(duì)象的查找和查找后的操作應(yīng)獨(dú)立成兩個(gè)不同類來完成,其中對(duì)對(duì)象的查找應(yīng)為一個(gè)RFTsuper class。其實(shí)也就是繼承了RationalTestScript類的抽象類,對(duì)對(duì)象的操作應(yīng)為一個(gè)Script,這個(gè)Scriptsuper class應(yīng)為自己之前定義的對(duì)象查找類,而不是默認(rèn)的RationalTestScript。這一部分后面還會(huì)講到。

          當(dāng)需要關(guān)閉可能出現(xiàn)的錯(cuò)誤窗口時(shí),可以這樣使用:

          if (aDialog.isDialog(".*Error"false)) {    
              aDialog.close();    
          }
           
           

          當(dāng)需要操作一定出現(xiàn)的窗口時(shí),可以這樣使用:

          if (aDialog.isDialog("Warning"true)) {   
              aDialog.clickButton(
          "Yes");   
          }
            
           

          至此,所有針對(duì)窗體的處理邏輯就基本完整了。當(dāng)然,可能有些被測(cè)程序可以同時(shí)打開多個(gè)實(shí)例,這就需要支持同時(shí)獲取并操作多個(gè)具有相同標(biāo)題的窗體。這樣的問題大家可以一同探討如何處理。

          posted @ 2009-03-21 20:57 terrypang 閱讀(1244) | 評(píng)論 (1)編輯 收藏

           

          經(jīng)過這些年的使用,我認(rèn)為RFT是一個(gè)十分優(yōu)秀的自動(dòng)化測(cè)試工具。尤其是目前的7.0.1.2版本,已經(jīng)非常穩(wěn)定,非常好用了。

          與大多數(shù)其它自動(dòng)化測(cè)試工具一樣,RFT提供了很多基礎(chǔ)設(shè)施,例如:對(duì)象的映射、動(dòng)作的錄制/回放、檢查點(diǎn)、數(shù)據(jù)池、HtmlTxT格式的報(bào)告等等。這些基礎(chǔ)設(shè)施確實(shí)能夠大幅度提升這一工具的上手速度,但是我以為,正是這些基礎(chǔ)設(shè)施使得RFT的使用者在使用過程中忽略了對(duì)這些基礎(chǔ)設(shè)施背后內(nèi)容的了解,以至于出現(xiàn)了問題束手無策。其實(shí),RFT是一個(gè)開放的自動(dòng)化測(cè)試開發(fā)平臺(tái),幾乎所有他所提供的基礎(chǔ)設(shè)施都有相應(yīng)的API暴露給使用者,只要用好這些API,就能夠非常輕松的定制出適合自己的自動(dòng)化測(cè)試框架,運(yùn)行中出現(xiàn)問題也非常容易定位分析。

          使用RFT有一段時(shí)間的人,應(yīng)該知道IBM有一個(gè)ITCL庫,是專門針對(duì)RFT的,他封裝了很多有用的方法,形成了一套開發(fā)框架,能夠明顯提高開發(fā)效率。不過,遺憾的是,這個(gè)庫非常的老(大部分類生成日期都是05年),如果你使用最新的RFT7.0,由于很多底層API都變化了,這個(gè)庫有不少部分都不能用了。

          如果你仔細(xì)閱讀過這個(gè)庫,你就會(huì)發(fā)現(xiàn)RFT是一個(gè)多么靈活的工具,也正因?yàn)檫@一點(diǎn),很多人都不明白如何能夠正確的使用RFT。在我看來,RFT使用的最佳實(shí)踐就是開發(fā)屬于自己的測(cè)試框架。只有這樣才能發(fā)揮RFT的真正威力。

          利用這個(gè)系列,我結(jié)合手頭的一個(gè)Swing界面的項(xiàng)目,介紹一下如何開發(fā)自己的測(cè)試框架。(Swing項(xiàng)目,運(yùn)行之間不要忘記Enable Jvm)。

          這里,作為測(cè)試框架,不應(yīng)使用對(duì)象映射,而應(yīng)該完全依賴于動(dòng)態(tài)查找。這是因?yàn)樗鼑?yán)重依賴RFT提供的基礎(chǔ)設(shè)施,靈活性很差。具體內(nèi)容隨后將逐一介紹。

          posted @ 2009-03-21 20:48 terrypang 閱讀(1140) | 評(píng)論 (0)編輯 收藏
          僅列出標(biāo)題  

          導(dǎo)航

          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          統(tǒng)計(jì)

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 电白县| 萨迦县| 富蕴县| 习水县| 洛阳市| 利津县| 怀集县| 集安市| 永寿县| 孟津县| 万源市| 香港| 闵行区| 昭苏县| 望江县| 乡宁县| 镇巴县| 顺义区| 洞头县| 德保县| 洛隆县| 沙湾县| 东城区| 林西县| 辉南县| 临安市| 瑞昌市| 定远县| 深州市| 霍林郭勒市| 祁门县| 齐齐哈尔市| 安阳县| 合肥市| 沽源县| 加查县| 新巴尔虎右旗| 新乐市| 扶沟县| 龙胜| 宁远县|