<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

    借鑒ASP.NET的控件模型輔助UI自動(dòng)化測(cè)試

      概述

      在敏捷測(cè)試中UI的自動(dòng)化測(cè)試(一般我們也稱這層測(cè)試為功能測(cè)試或驗(yàn)收測(cè)試,本文單指Web UI的自動(dòng)化測(cè)試)雖然沒(méi)有單元測(cè)試那么廣為提及,但因?yàn)槠渑c最終用戶最近,所以基于用戶場(chǎng)景的UI自動(dòng)化測(cè)試還是有其重要的意義的。使用UI自動(dòng)化測(cè)試對(duì)產(chǎn)品的關(guān)鍵功能路徑進(jìn)行驗(yàn)證及回歸,比起傳統(tǒng)的QA手工執(zhí)行Test case可以更快地得到反饋,也讓發(fā)布變得更有信心。

       理想狀況下,我們應(yīng)該將所有可以固化下來(lái)的Test case都自動(dòng)化起來(lái),而讓我們的測(cè)試人員進(jìn)行更有挑戰(zhàn)性的探索性測(cè)試活動(dòng)。讓機(jī)器做已知領(lǐng)域的事兒,讓人對(duì)未知領(lǐng)域進(jìn)行探索。不過(guò)理想歸理想,現(xiàn)實(shí)是殘 酷的。雖然UI層的測(cè)試距離交付最近,但是成本也最高。編寫(xiě)和維護(hù)UI自動(dòng)化測(cè)試需要付出比其他自動(dòng)化測(cè)試更高昂的成本,這也是大多數(shù)團(tuán)隊(duì)放棄UI自動(dòng)化 測(cè)試的主要原因。相比較系統(tǒng)的其他部分,UI是一個(gè)多變的層,如果UI自動(dòng)化測(cè)試沒(méi)有構(gòu)建好,即使界面的一個(gè)微小改動(dòng),整個(gè)測(cè)試集可能就天崩地裂。這也就 是為什么我經(jīng)常對(duì)team里其他人說(shuō):對(duì)于UI自動(dòng)化測(cè)試,可維護(hù)性必須牢記心頭。每當(dāng)你寫(xiě)下一行測(cè)試代碼時(shí),你就必須記住你又給公司添加了一筆成本,而 且這個(gè)成本是持續(xù)增長(zhǎng)的,如果review code的時(shí)候發(fā)現(xiàn)哪條測(cè)試代碼維護(hù)性不好我會(huì)毫不猶豫的刪掉。

      或許有人覺(jué)得這有點(diǎn)小題大作,不就UI測(cè)試么,有什么難的。定位元素,然后拿到頁(yè)面元素的值與期望進(jìn)行比較不就可以了。難就難在定位元素上。一般我們會(huì)使用Selenium WebDriver, Watir, Sahi等工具驅(qū)動(dòng)瀏覽器,進(jìn)行元素定位(關(guān)于這些工具的詳細(xì)使用可以參見(jiàn)官方文檔,后文主要以Selenium WebDriver為示例)。這些工具在定位元素上基本上是大同小異:通過(guò)id, name, css, tagName, xpath等方式定位。這些定位方式,從前到后,一個(gè)比一個(gè)不靠譜。比如這個(gè)xpath,好不容易寫(xiě)出個(gè)xpath定位,然后突然有一天前端覺(jué)得某個(gè)地方 不美觀,插入一個(gè)小東西,馬上測(cè)試廢掉。看著這種沒(méi)有改變功能也把功能測(cè)試搞垮掉的現(xiàn)象是不是欲哭無(wú)淚。我有時(shí)天真的在想如果頁(yè)面上每一個(gè)元素都有唯一的 id該多好啊。即使沒(méi)有唯一的id,有name我也可以接受。不過(guò)這一切在遇到ExtJS之后都變了。

      遭遇ExtJS

      ExtJS是一個(gè)非常霸道的前端框架。使用ExtJS后,頁(yè)面上幾乎所有的一切都被ExtJS接管。盡管互聯(lián)網(wǎng)提 供給用戶的系統(tǒng)鮮有使用ExtJS,但是對(duì)于后臺(tái)系統(tǒng)使用ExtJS確實(shí)帶來(lái)了一些便利。使用ExtJS的基本組件就能組裝出一個(gè)看起來(lái)還不錯(cuò),功能強(qiáng)大 的應(yīng)用。但是ExtJS非常霸道,被他接管后頁(yè)面的生成基本上就是個(gè)黑盒子,而為了在各個(gè)瀏覽器的兼容它在各瀏覽器上生成的html還不一樣。更可恨的是 默認(rèn)情況下它給元素提供的id都是動(dòng)態(tài)生成的。

      在剛選擇這個(gè)ExtJS的系統(tǒng)作為我們自動(dòng)化測(cè)試的第一個(gè)試點(diǎn)時(shí),我還有點(diǎn)暗暗高興。比 起那些提供給普通用戶使用的豐富多彩的前端來(lái)說(shuō),這些后臺(tái)系統(tǒng)大多中規(guī)中矩,使用ExtJS后更是層次分明。而且后臺(tái)系統(tǒng)UI的變動(dòng)也不會(huì)太過(guò)于頻繁,我 想或許這個(gè)系統(tǒng)很容易測(cè)試吧。

      后來(lái)我看到同事代碼里出現(xiàn):

    webDriver.findElement(By.id("ext-gen-1306"))

       我還在想,我們的前端同學(xué)真有“創(chuàng)意”,還用這么隨機(jī)的名字啊。后來(lái)厄運(yùn)來(lái)了,我check out代碼在我這里死活通過(guò)不了。Selenium報(bào)告找不到指定元素。不是吧,我可是使用id進(jìn)行定位的啊。通過(guò)翻閱ExtJS的文檔發(fā)現(xiàn),原來(lái)類(lèi)似 ext-gen-xxx這類(lèi)id都是ExtJS動(dòng)態(tài)生成的。好吧,我使用name進(jìn)行定位吧,后來(lái)發(fā)現(xiàn)很多元素居然沒(méi)有name屬性。再來(lái)看看ExtJS 生成的html,基本上把通過(guò)xpath進(jìn)行定位的路給堵死了。要了解ExtJS生成的html,可以去ExtJS官方查看一些Demo。

      曙光

       閱讀ExtJS文檔我們發(fā)現(xiàn),ExtJS極其強(qiáng)調(diào)它的組件模型。而用ExtJS寫(xiě)的前端代碼也呈現(xiàn)出很好的結(jié)構(gòu)。因?yàn)橹霸鴱氖逻^(guò)ASP.NET的開(kāi) 發(fā),我想是不是可以使用ASP.NET類(lèi)似的方式先編寫(xiě)一些小控件類(lèi),這些類(lèi)對(duì)ExtJS的基本組件進(jìn)行包裝。然后利用這些小控件類(lèi)組裝出一個(gè)個(gè)頁(yè)面。這 樣不僅能把單個(gè)元素的定位分散到單個(gè)控件類(lèi)里,而且可以做到極大程度的復(fù)用。在傳統(tǒng)的UI自動(dòng)化測(cè)試中我們使用Page Object模式來(lái)封裝一個(gè)個(gè)頁(yè)面,但是對(duì)于ExtJS來(lái)講頁(yè)面的粒度還顯得過(guò)大。如是模仿ASP.NET的控件模型,我創(chuàng)建了Control, Button, TextBox等一系列基本的控件類(lèi)。而原來(lái)Page Object中的Page不再使用WebDriver直接定位元素了,我們通過(guò)這些基本控件組裝頁(yè)面。

      實(shí)現(xiàn)

      在這里我用一個(gè)簡(jiǎn)單的用戶登錄作為例子:

      Control是我們的基本類(lèi)型,所有的控件包括頁(yè)面都從這個(gè)類(lèi)派生。

      Control只提供了很少幾個(gè)方法:

    public abstract class Control {
        protected WebDriver webDriver;


        protected Control parent;


        public Control(WebDriver webDriver) {
            this.webDriver = webDriver;
        }


        public String getQuery() {
            return StringUtils.EMPTY;
        }


        public String getId() {
            JavascriptExecutor executor = (JavascriptExecutor) webDriver;
            return (String) executor.executeScript("return " + this.getQuery() + ".id");
        }
    }
     在這里getQuery是一個(gè)非常重要的方法,這在后面會(huì)介紹。

    public abstract class CompositeControl extends Control {
        protected List <Control> children;


        public CompositeControl(WebDriver webDriver) {
            super(webDriver);
            children = new ArrayList<Control> ();
        }


        public void addChild(Control control) {
            this.children.add(control);
            control.parent = this;
        }
    }

      所有的可以包含其他控件的類(lèi)型都從CompositeControl派生,包括Page。比如下面的Window就是這類(lèi)元素:

    public class Window extends CompositeControl {
        private String title;


        public Window(String title,WebDriver webDriver) {
            super(webDriver);
            this.title = title;
        }


        @Override
        public String getQuery(){
            return String.format("Ext.ComponentQuery.query(\"window[title='%s']\")[0]",title);
        }
    }

      下面是一個(gè)基本控件Button的封裝:

    public class Button extends Control {
        private String text;


        public Button(String text, WebDriver webDriver) {
            super(webDriver);
            this.text = text;
        }


        @Override
        public String getQuery() {
            return this.parent.getQuery() + String.format(".query(\"button[text='%s']\")[0]", text);
        }


        public void click() {
            webDriver.findElement(By.id(getId())).click();
        }
    }

      ExtJS提供了一個(gè)query接口,我們可以利用這個(gè)接口傳入一些查詢表達(dá)式查詢到頁(yè)面上的Ext控件,而這里的getQuery就是每個(gè)控件的查詢表達(dá)式吧。因?yàn)轫?yè)面上的ExtJS控件是層次的,所以我們可以利用這種嵌套關(guān)系進(jìn)行精確的定位。

      好了,來(lái)看看我們的登陸頁(yè)面如何封裝吧:

    public class LoginPage extends ExtJSPage{
         public LoginPage(WebDriver webDriver){
              super(webDriver);
         }


         private TextBox txtUserName;
         private TextBox txtPassword;
         private Button btnLogin;
        
         @Override
         protected void init(){
              txtUserName = new TextBox("userName", webDriver);
              txtPassword = new TextBox("password", webDriver);
              btnLogin = new Button("登錄", webDriver);


              Window win = new Window("登陸", webDriver);
              win.addChild(txtUserName);
              win.addChild(txtPassword);
              win.addChild(btnLogin);


              this.addChild(win);
         }


         public void login(String userName, String password){
              txtUserName.setValue(userName);
              txtPassword.setValue(password);
              btnLogin.click();
         }
    }

      上面的TextBox和ExtJSPage沒(méi)有提供代碼,都很簡(jiǎn)單可以自行進(jìn)行封裝一下(熟悉ASP.NET的同學(xué)可能對(duì)這里代碼有點(diǎn)眼熟)。

      按照這種思路,只要我們封裝好所有的基本ExtJS控件,對(duì)于所有的頁(yè)面我們剩下的工作就是組裝的工作了。在完成這些之后,我甚至發(fā)現(xiàn)使用 ExtJS的應(yīng)用比那些沒(méi)有使用ExtJS的應(yīng)用更容易進(jìn)行測(cè)試。在這里我們只需要完善我們的基本控件封裝就可以讓我們的測(cè)試更佳穩(wěn)固,而對(duì)于編寫(xiě)測(cè)試的 人來(lái)說(shuō)只需要集中精力關(guān)注Test case。

    posted on 2012-06-01 09:56 順其自然EVO 閱讀(255) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): selenium and watir webdrivers 自動(dòng)化測(cè)試學(xué)習(xí)

    <2012年6月>
    272829303112
    3456789
    10111213141516
    17181920212223
    24252627282930
    1234567

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(55)

    隨筆分類(lèi)

    隨筆檔案

    文章分類(lèi)

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲精品人成在线观看| 啦啦啦手机完整免费高清观看| 99在线视频免费观看| 成人片黄网站色大片免费观看cn| 无码免费又爽又高潮喷水的视频| 免费的黄色的网站| 一区二区三区免费精品视频 | 黑人大战亚洲人精品一区| 精品国产香蕉伊思人在线在线亚洲一区二区| 亚洲国产精品无码久久九九| 亚洲天堂免费在线视频| 国产亚洲情侣一区二区无| 久久91亚洲人成电影网站| 亚洲AV成人精品网站在线播放| 亚洲黄网在线观看| 亚洲sss综合天堂久久久| 亚洲日本va一区二区三区 | 亚洲激情中文字幕| 亚洲制服丝袜在线播放| 亚洲久热无码av中文字幕| 国产精品亚洲а∨无码播放麻豆 | 在线观看亚洲AV日韩A∨| 国产精品亚洲专一区二区三区| 国产精品免费久久| 久久爰www免费人成| 国产va精品免费观看| 国产高清在线精品免费软件| 国产成人高清亚洲| 99久久亚洲综合精品成人网| 天堂亚洲国产中文在线| 美女羞羞喷液视频免费| 中文字幕乱码一区二区免费| 黄色永久免费网站| 大胆亚洲人体视频| 婷婷精品国产亚洲AV麻豆不片| 亚洲中文久久精品无码1| 猫咪www免费人成网站| 色猫咪免费人成网站在线观看| 最近中文字幕免费mv视频7| 亚洲国产成人久久一区久久| 久久久久亚洲av无码专区|