新聞中心
摘要

創(chuàng)新互聯(lián)公司主要業(yè)務(wù)有網(wǎng)站營銷策劃、網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開發(fā)、小程序制作、H5技術(shù)、程序開發(fā)等業(yè)務(wù)。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當(dāng)客戶,還把客戶視為我們的合作伙伴,在開展業(yè)務(wù)的過程中,公司還積累了豐富的行業(yè)經(jīng)驗(yàn)、網(wǎng)絡(luò)營銷推廣資源和合作伙伴關(guān)系資源,并逐漸建立起規(guī)范的客戶服務(wù)和保障體系。
無論你開發(fā)大或小的應(yīng)用, 從安全來講測(cè)試是一個(gè)很重要的組成部分.
但是如何可靠持續(xù)的測(cè)試, 尤其是當(dāng)你的人員不能有效的測(cè)試應(yīng)用的每一次改變? 所以呢,把這個(gè)工作交給軟件是最合適的了.
這么多年來, 開發(fā)者開發(fā)了很多應(yīng)用和技術(shù)來滿足這個(gè)需求. 當(dāng)然, 它們運(yùn)行的非常好. 但是我們總是尋找更新的, 更簡(jiǎn)單的 (有時(shí)候是更'酷'的) 方式來做我們的工作. 所以最近我開始學(xué)習(xí)一種更有前途的新技術(shù): PhantomJS.
PhantomJS是什么?
PhantomJS 是一個(gè)無界面的,包含了WebKit瀏覽器引擎和JavaScript API的腳本解釋器. 速度快并且支持各種web標(biāo)準(zhǔn): DOM 操作, CSS 選擇器, JSON, Canvas 和SVG.
PhantomJS 的創(chuàng)建者是 Ariya Hidayat. 它是一個(gè)非常棒的技術(shù),但是通過網(wǎng)站上的了解和所有的APIs文檔, 我遇到了 CasperJS.
CasperJS是什么?
Casper 是一個(gè)用JavaScript編寫的基于PhantomJS的導(dǎo)航腳本和測(cè)試工具.它充許我們像PHPUnit或 JUnit一樣測(cè)試我們的網(wǎng)站,測(cè)試我們的代碼.
它是一個(gè)非常棒的工具 – 一是它是非常簡(jiǎn)單的,用JavaScript編寫,滿足各種各樣的測(cè)試需求,一是它可以方便的和我們的開發(fā)環(huán)境集成. 完美的組合前端和后端.
這本篇文章中,我將瀏覽一下CasperJS的基礎(chǔ)用法。我將扮演一個(gè)典型的用戶訪問New Relic(新的遺址)網(wǎng)站的一頁,特別是‘真實(shí)用戶監(jiān)控’部分。
我之所以選擇這一頁是因?yàn)樗写罅糠矫鎸?duì)一個(gè)標(biāo)準(zhǔn)網(wǎng)站或應(yīng)用極為常見,如圖像,表單,按鈕,鏈接和文本。它內(nèi)容豐富并且有許多東西可供我們處理與測(cè)試?,F(xiàn)在,我確信New Relic的勤快的伙計(jì)已經(jīng)做過這些,但我也非常相信他們不會(huì)介意我為這個(gè)網(wǎng)站建立一個(gè)簡(jiǎn)單的測(cè)試集和斷言。
特征
CasperJS具有一系列特征。 本文中,我會(huì)聚焦于 測(cè)試人員 API。它具有一些列功能與斷言,都是你期望一個(gè)好的測(cè)試API所具有的,包括:
* assertTextExists (文本存在斷言)
* assertTitle (標(biāo)題斷言)
* assertHttpStatus (HTTP狀態(tài)斷言)
* assertDoesntExist (不存在斷言)
* assertUrlMatch (Url匹配斷言)
我將使用這些斷言來顯示CasperJS是如何工作的。它也包含一組其他特性,但我不會(huì)去深入探討——僅僅足夠做一個(gè)工作示例而已。不過,我鼓勵(lì)你研究一下精彩的在線API文檔。它閱讀起來令人愉悅,因?yàn)樗喈?dāng)清晰和簡(jiǎn)潔。
準(zhǔn)備
如果你沒有準(zhǔn)備好,在我們繼續(xù)以前,先安裝 PhantomJS 或 Casper 。 現(xiàn)在,讓我們馬上開始吧。
開始
當(dāng)我第一次加載New Relic網(wǎng)站的'真實(shí)用戶監(jiān)控'頁面,看起來像下面圖片這樣(自撰寫本文以后它已經(jīng)變化了)。我突出了注冊(cè)表格的起點(diǎn)。
如果你點(diǎn)擊了這個(gè)表單里的任何元素,它其余的部分就會(huì)顯露出來,看起來就是下圖這樣。
測(cè)試將著眼于表單,但我們也要看看title標(biāo)簽,表單左邊的圖片,及其上的文字。
#p#
代碼:
首先,為節(jié)省時(shí)間,我初始化了兩個(gè)變量:一個(gè)用來存儲(chǔ)URL,一個(gè)用來存儲(chǔ)網(wǎng)站名稱,因?yàn)槲乙跍y(cè)試中的‘success’信息里顯示它們。
- var url = 'http://newrelic.com/product/real-user-monitoring';
- var siteName = 'NewRelic';
Casper帶有4個(gè)內(nèi)建記錄級(jí)別:
* debug
* info
* warning
* error
默認(rèn)情況下,CasperJS會(huì)在‘error’級(jí)別過濾日志。所以如果你開始記錄日志后沒有看到任何東西,可能就是這個(gè)原因。為確保顯示日志輸出,我把它設(shè)置為‘debug’。而且我關(guān)閉了‘verbose’選項(xiàng),如果它激活,我們會(huì)看到關(guān)于所有東西的信息,這會(huì)相當(dāng)干擾。
- var casper = require('casper').create({
- verbose: false,
- logLevel: 'debug'
- });
你可以在Casper API頁面上發(fā)現(xiàn)其它配置選項(xiàng)。comment函數(shù),如下面演示的,使我們能記錄輸出——在這種情況下是輸出到控制臺(tái)。我在這里使用一個(gè)簡(jiǎn)單的消息說明測(cè)試開始了:
- casper.test.comment('Starting Testing');
函數(shù)‘casper.start’開始運(yùn)行測(cè)試:
- casper.start(url, function() {
- this.test.assert(
- this.getCurrentUrl() === url, 'url is the one expected'
- );
- this.test.assertHttpStatus(200, siteName + ' is up');
這是我所做的:我加載在‘url’中指定的URL,并假定我們可以載入想要的網(wǎng)址。在成功加載頁面之后,開始調(diào)用一些斷言來確認(rèn)所載入的頁面上的內(nèi)容是我們所期望的。
在這種情況下,我對(duì)返回的狀態(tài)碼進(jìn)行了一個(gè)快速檢查,它應(yīng)該是200,我得到的也是200。讓我們進(jìn)行另一個(gè)斷言:
- this.test.assertTitle(
- 'Real User Monitoring, End User Experience Monitoring : New Relic',
- siteName + ' has the correct title'
- );
上面這個(gè)測(cè)試非常簡(jiǎn)單。它斷言載入的頁面的標(biāo)題應(yīng)該是什么,并輸出一個(gè)含有該信息的消息。
在下面的代碼里,我首先檢查確認(rèn)存在一個(gè)ID為‘nr-signup-form’的表單。如果這個(gè)表單不存在,那對(duì)表單內(nèi)的元素進(jìn)行檢查就沒有意義了,對(duì)吧?
- this.test.assertExists(
- 'form[id="nr-signup-form"]',
- siteName + ' has a form with name "nr-signup-form"'
- );
現(xiàn)在,在我繼續(xù)之前,我要提到的是,當(dāng)我斷言元素存在或不存在于加載的頁面上時(shí),我可以用兩種不同的方法:
* XPath
* CSS選擇器
如果你想要更多XPath的信息,請(qǐng)檢閱后面‘延伸閱讀’部分中的一些相關(guān)鏈接,或閱讀 我寫并發(fā)到maltblue的文章。CSS選擇器應(yīng)該有很好的自我解釋性。但為以防萬一,我在“延伸閱讀”部分中同樣包含了關(guān)于它的鏈接。
現(xiàn)在讓我們用斷言來搜索輸入域控件:
- this.test.assertExists(
- {type: 'xpath', path: '//input[@id="FullName"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//input[@id="Company"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//input[@id="Email"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//input[@id="Password"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//input[@id="PromoCode"]' },
- 'the element exists'
- );
在上面的五個(gè)斷言中,我查找了五個(gè)輸入域控件,它們的ID分別是‘FullName’, ‘Company’, ‘Email’, ‘Password’ 和‘PromoCode’。用XPath查找選擇列表控件元素同樣容易。
#p#
在下面的測(cè)試中,我假定有四個(gè)選擇列表控件,它們的ID分別是:‘country’, ‘group’, ‘company_size’ 和‘HostEstimate’。
- this.test.assertExists(
- {type: 'xpath', path: '//select[@id="country"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//select[@id="group"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//select[@id="company_size"]' },
- 'the element exists'
- );
- this.test.assertExists(
- {type: 'xpath', path: '//select[@id="HostEstimate"]' },
- 'the element exists'
- );
現(xiàn)在,這些測(cè)試還非常簡(jiǎn)單。那么,讓我們來把它們變得復(fù)雜點(diǎn)。
- this.test.assertExists(
- {
- type: 'xpath',
- path: '//button[@id="sign-up-button"
- and @class="small-button"
- and @type="submit"]'
- }, 'the element exists'
- );
在上面的測(cè)試中,我搜索‘Create Free Account’按鈕,它在頁面中的位置如下圖所示。
我在查詢中使用了一些條件運(yùn)算符。我們要尋找一個(gè)具有下列條件的按鈕:
* ID 為 ‘sign-up-button’
* class 為‘small-button’
* type 為‘submit’
雖然看起來似乎我關(guān)注XPath比CasperJS更多,但為了更多的功能和配置,請(qǐng)耐心忍受我多說一點(diǎn)吧。
- var x = require('casper').selectXPath;
- var checkboxXpath = "http://input[@type='checkbox' and
- @id='checkbox1']/parent::*/a/label[
- contains(., 'Java') or
- contains(., 'Python') or
- contains(., 'Ruby') or
- contains(., 'PHP') or
- contains(., '.NET') or
- contains(., 'Node.js')
- ]";
- this.test.assertExists(x(checkboxXpath), 'the element exists');
我在上面的測(cè)試中所做的,是通過把'x'初始化為‘selectXPath’助手來使XPath測(cè)試變得簡(jiǎn)化一點(diǎn)。我要查找那一頁上所有選擇應(yīng)用程序類型的復(fù)選框,所以XPath查詢查找復(fù)選框時(shí)用一個(gè)伴隨的label標(biāo)簽來匹配所提供的應(yīng)用程序語言的名稱。
為專門顯示我并非只會(huì)使用XPath(雖然它極其強(qiáng)大而且簡(jiǎn)單),下面的兩個(gè)測(cè)試也使用CSS選擇器來檢查一個(gè)輸入域控件和列表項(xiàng)目也存在。
- this.test.assertVisible('input#Company');
- this.test.assertExists('li.nav-enterprise', 'the element exists');
搜索表單元素和列表項(xiàng)目很簡(jiǎn)單,但若你的頁面有很多資源,對(duì)于圖片或Flash的載入又怎么檢測(cè)呢?這有一個(gè)例子:
- this.test.assertResourceExists(
- '/images/tshirt-dude-form.png', 'T-shirt Image exists'
- );
對(duì)于上面的測(cè)試,我斷言穿著所展示T恤的男人的照片已載入。 最后一個(gè)測(cè)試斷言某些文本存在,在本情況中就是在穿著T恤的男人鏡頭上方的‘Sign up for free!’文本:
- this.test.assertTextExists(
- 'Sign up for free!', 'page body contains "Sign up for free!"'
- );
然后我們這樣結(jié)束‘start’函數(shù):
- casper.test.comment('Ending Testing');
測(cè)試基本完成了,所以我輸出另一個(gè)日志記錄來讓用戶知道這一點(diǎn):
- casper.run(function() {
- this.test.done(16);
- this.echo('So the whole suite ended.');
- require('utils').dump(casper.test.getFailures());
- require('utils').dump(casper.test.getPasses());
- this.exit();
- });
我可以寫出我想要的所有測(cè)試,但若不調(diào)用“run”則什么都不會(huì)發(fā)生。所以“run”是揭開上述工作的序幕。我所做的是檢查腳本是否已經(jīng)運(yùn)行了16個(gè)測(cè)試,并且在最后用‘this.echo()’輸出最后一行文字表示整個(gè)測(cè)試已結(jié)束。
當(dāng)我們運(yùn)行測(cè)試時(shí),有時(shí)得到最后結(jié)果的總結(jié)會(huì)挺好。用‘getFailures()’ 和 ‘getPasses()’函數(shù),我們可以看到測(cè)試通過和失敗的總結(jié)。跟在這一切最后,我調(diào)用“this.exit()”來清盤。這個(gè)可以退出 CasperJS和PhantomJS,如果需要,可以指定一個(gè)退出編號(hào)。
把這個(gè)更進(jìn)一步,這一次我調(diào)用‘casperjs’略有不同:我傳遞‘test’,如下所示,伴隨著“xunit”開關(guān)。 這個(gè)將測(cè)試結(jié)果輸出到一個(gè) XUnit XML文件.
- $ casperjs test mytest.js --xunit=log.xml
在CasperJS的下一個(gè)主要版本中,如果‘test’沒被傳遞到命令中,你將無法運(yùn)行和呈現(xiàn)測(cè)試。提前知道這個(gè)很重要,可以避免你的腳本被意外打斷。
#p#
自動(dòng)化測(cè)試
你是否想通過設(shè)置來自動(dòng)化你的測(cè)試?我的意思是,我們可以手工進(jìn)行一些測(cè)試,那很棒,但它令人乏味且很費(fèi)時(shí)。令人高興的是,有一個(gè)擴(kuò)展有助于你進(jìn)行自動(dòng)化測(cè)試。當(dāng)我開始寫這個(gè)系列時(shí)沒有意識(shí)到這一點(diǎn)。我想給@casperjs_org一個(gè)巨大感謝,他使我意識(shí)到谷歌瀏覽器的擴(kuò)展resurectio。
克隆或下載一個(gè)拷貝并安裝它,然后重新打開我們之前用過的 New Relic頁,在擴(kuò)展按鈕列表中點(diǎn)擊‘resurectio’。
在你想構(gòu)成一個(gè)自動(dòng)測(cè)試的網(wǎng)頁上,單擊網(wǎng)頁地址欄里的“Go(轉(zhuǎn)入)”。從現(xiàn)在開始你所做的任何事情都將被包含成為生成的測(cè)試腳本的一部分。
我點(diǎn)遍每個(gè)表單元素,從“Email”到“Company Size”。然后再次點(diǎn)擊擴(kuò)展按鈕以停止錄制,接著點(diǎn)擊'Export CasperJS”,這會(huì)在瀏覽器中打開另一個(gè)頁面來顯示所生成的腳本。
復(fù)制那些到一個(gè)腳本,運(yùn)行它,你會(huì)看到和我們先前創(chuàng)造的腳本一樣,你會(huì)得到象下面的截圖中看到的輸出。
如你的見,它能很好地完成設(shè)置環(huán)境和建立所有測(cè)試斷言的工作,我們所做的就是運(yùn)行它。這使得用CasperJS來讓測(cè)試準(zhǔn)備就緒變得十分容易。
延伸閱讀
* XPath
* CSS選擇器參考
* 安裝CasperJS
* PhantomJS
* JUnit
* PHPUNit
結(jié)論
我希望你喜歡這個(gè)對(duì) CasperJS 的溫柔介紹,欣賞它給我們的威力和靈活性,通過phantomjs去設(shè)計(jì)深入的用戶接受測(cè)試套件。
我們看到我們能怎樣用最少的努力去測(cè)試New Relic網(wǎng)站的‘Real User Monitoring’頁面的內(nèi)容,盡管要有一些手動(dòng)的工作來確定所需的XPath表達(dá)式和CSS選擇器。
但對(duì)于一個(gè)免費(fèi)的解決方案來說,它確實(shí)提供了很多的能力。我相信你會(huì)同意這個(gè)觀點(diǎn)。所以你覺得它怎么樣?你能預(yù)見到你或你的組織將它作為你的部署 和/或 持續(xù)集成解決方案的一部分嗎?
在下一部分,我將從測(cè)試中叉出來講casperjs的其它部分,包括:
* HTTP 身份認(rèn)證
* 鼠標(biāo)事件
* 表單提交
* 冒充用戶代理
* 制作AJAX請(qǐng)求
英文原文:Simpler UI Testing with CasperJS
譯文鏈接:http://www.oschina.net/translate/simpler-ui-testing-with-casperjs
分享名稱:使用CasperJS進(jìn)行簡(jiǎn)單的UI測(cè)試
網(wǎng)址分享:http://m.5511xx.com/article/cdphphc.html


咨詢
建站咨詢
