UI自動化測試框架 ---TestCafe(轉)


什么是TestCafe

轉自: https://www.jianshu.com/p/94181abe5e9a

 

官方:

A node.js tool to automate end-to-end web testing Write tests in JS or TypeScript, run them and view results 

抓幾個重點詞語:1. E2E Web Testing 2.JS\TypeScript 3. Node.js Tool。
簡單說就是Node.JS編寫的Web端UI自動化測試框架。
官網:http://devexpress.github.io/testcafe/

TestCafe VS Selenium

這時我想你跟我都有個疑問,跟Selenium 有啥區別?這里個人簡單閱讀了下官方文檔,寫幾個粗淺的對比。

對比項 Selenium 3.x TestCafe 誰更優
社區 Web自動化測試一哥 ,學習資料非常多 較新的工具,官方提供了詳細的學習資料,Github上Start人數也超過5K Selenium
支持語言 java,python,ruby,Node.js...... JavaScript,TypeScript Selenium
支持的瀏覽器 Chrome,IE,Firefox,Safari,Edge等有Driver的瀏覽器都支持 支持所有能支持JS的瀏覽器,也就意味着支持多端 TestCafe
完善性 需要跟其它框架結合使用,如TestNG等 自身就是一個完整的自動化測試框架 TestCafe
易學性 簡單易學 簡單易學 不分上下

Selenium畢竟已經是Web自動化測試的W3C標准了,它有非常多的優勢,但TestCafe 作為后起之秀我這還想誇誇Demo使用過程的幾點優於Selenium的感受。

  • TestCafe 不再像Selenium 通過各個瀏覽器提供的Driver來驅動瀏覽器,而是有點類似Selenium RC直接往頁面注入JS來操作頁面,所以使用過程中再也不用擔心因為瀏覽器版本和Driver版本以及Selenium版本不匹配而照成的Case執行失敗。
  • TestCafe 是一整套完整的自動化測試框架,不僅提供了Cases的管理,運行,失敗自動重跑,錯誤自動截圖,並發等,對頁面和頁面元素的等待也封裝完善而且使用簡單,不像Selenium需要借助其他框架或者二次封裝智能等待或者使用隱示/顯示等待而有點復雜。
  • TestCafe 可以控制整體的執行速度,甚至可以細到某個操作的執行速度(這個有點類似慢放,用起來大家可以感受下,非常魔性)
  • TestCafe 因為只要你的瀏覽器支持JS,所以支持桌面,移動端平台。
  • TestCafe debug模式,通過代碼配置或運行時設置,可以控制執行過程中失敗時進入調試模式。

PS:當然以上的感受並沒有經過項目的積累,純粹Demo過程中的總結,也不曉得真正用到項目中會有哪些坑得踩。

TestCafe 快速入門

安裝

因為是Node.js 項目,可以直接通過npm安裝,全局安裝如下

npm install -g testcafe

快速Demo一個

baidu.js

fixture `baidu demo`
    .page `https://www.baidu.com`; test('baidu search', async t=>{ await t.typeText('#kw',"hao123") .click('#su') }); 

通過Chrome運行

testcafe chrome baidu.js

上面代碼看不懂沒關系,感受下TestCafe就行。

Cases管理

自動化測試,終歸還是測試,是測試就離不開測試用例,那TestCafe如何組織管理測試用例?

fixture 和 test

一個js文件可以包含多個fixture,一個fixture可以包含多個test。 我們可以理解為fixture是個集合,test標注的每個函數模塊是一個case。

語法

fixture("測試集描述")
fixture `測試集合描述`
test('用例描述',fn(t))

Demo

fixture("cases manage").page("https://www.baidu.com"); test('this case 1', async I => { console.log("this is case 1"); }); test('this case 2', async I => { console.log("this is case 2"); }); test('this case 3', async I => { console.log("this is case 3"); }); fixture(`cases manage 2`).page(`https://testerhome.com/#gsc.tab=0`); test('this case 1-1', async I => { console.log("this is case 1-1"); }); test('this case 2-1', async I => { console.log("this is case 2-1"); }); test('this case 3-1', async I => { console.log("this is case 3-1"); }); 

運行結果:


 
image.png

其中你會發現每個test 執行之前都會執行fixture打開頁面的操作,但只會啟動一次瀏覽器。那這時又會一個新的問題,除了打開頁面的前提條件,是否框架自帶了更多的前提/后置條件的處理了,也就是各種beforexxx。
當然!

fixture 的前置條件

fixture.beforeEach( fn(t) ):每個test執行之前都會被運行
fixture.afterEach( fn(t) ):每個test執行之后都會被運行
fixture.before(fn(t)):比beforeEach更早運行,且每個fixture只運行一次
fixture.after(fn(t)):比afterEach更晚運行,且每個fixture只運行一次

Demoj


fixture(`beforeeach test1`) .page(`https://www.baidu.com`) .beforeEach(async I => { console.log('this is beforeEach') }) .before(async I => { console.log('this is before') }) .after(async I => { console.log('this is after') }) .afterEach(async I=>{ console.log("this is afterEach") }); test("test beforeAndafter",I=>{ console.log("1111") }); test("test beforeAndafter",I=>{ console.log("2222") }); 

運行結果:


 
image.png

test的前置條件

test.before(fun(t)):該test運行之前運行
test.after(fun(t)):該test運行之后運行

Demo

fixture(`beforeeach test1`) .page(`https://www.baidu.com`) .beforeEach(async I => { console.log('this is beforeEach') }) .before(async I => { console.log('this is before') }) .after(async I => { console.log('this is after') }) .afterEach(async I => { console.log("this is afterEach") }); test .before(async t => { console.log(`this is test's before`) }) ("test beforeAndafter", I => { console.log("1111") }) .after(async t => { console.log(`this is test's after`) }); test("test beforeAndafter", I => { console.log("2222") }); 

運行結果:


 
image.png

注意: 從控制台輸出看,test的before/after 會覆蓋fixture中的beforeEach/afterEach。也就是說如果一個test里面包含了before/after 那么fixture中的beforeEach/afterEach對該test無效。

跳過測試

fixture.skip :跳過該fixture下的所有test
test.skip : 跳過該test
fixture.only :只執行該fixture下的所有test,其余的fixture下的test全部跳過
test.only : 只運行該test,其余全部跳過

元素定位

Demo

  1. 創建Selectors
import { Selector } from 'testcafe'; 
  1. 使用Selectors
    // 通過css定位 const osCount = Selector('.column.col-2 label').count; // 通過id定位 const submitButtonExists = Selector('#submit-button').exists; 

同時因為是JS注入方式,所以定位方式非常靈活,幾乎JS中定位元素的方式都支持。 例如

import { Selector } from 'testcafe'; fixture `My fixture` .page `http://devexpress.github.io/testcafe/example/`; const label = Selector('#tried-section').child('label'); test('My Test', async t => { const labelSnapshot = await label(); await t.click(labelSnapshot); }); test('My test', async t => { const secondCheckBox = Selector('input') .withAttribute('type', 'checkbox') .nth(1); const checkedInputs = Selector('input') .withAttribute('type', 'checkbox') .filter(node => node.checked); const windowsLabel = Selector('label') .withText('Windows'); await t .click(secondCheckBox) .expect(checkedInputs.count).eql(1) .click(windowsLabel); }); 

同時還支持自定義擴展選擇器,而且針對當前流行的React,Vue,Angular,Aurelia前端框架,還有特點的定位選擇器,這里內容很多,有興趣直接看官方文檔:
http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/

操作

元素操作其實上面例子我們已經用過點擊,文本輸入等方法了,官方也給了很全的api文檔和demo:http://devexpress.github.io/testcafe/documentation/test-api/actions/ ,這里就講下一些比較特殊的元素或瀏覽器的操作。

  • resizeWindow():設置窗口大小
  • t.maximizeWindow( ):最大化窗口
fixture`demo`.page('https://www.baidu.com'); test('設置win窗口大小', async I => { await I.resizeWindow(300, 500) ..maximizeWindow( ); }); 
  • getBrowserConsoleMessages():獲取頁面控制台消息
test('獲取控制台輸出', async I => { console.log(await I.getBrowserConsoleMessages()) }); 
  • wait():暫停
test('暫停', async I => { await I.wait(3000); }); 
  • switchToIframe():切換到iframe
  • switchToMainWindow():返回到主窗體
fixture`iframe 處理 `
    .page`http://www.w3school.com.cn/tiy/t.asp?f=jseg_alert`; test('iframe ', async t => { await t .click('#button-in-main-window') // 切換ifrme .switchToIframe('#iframe-1') // 返回主窗體 .switchToMainWindow(); }); 
  • 下拉框選取:其實就是定位下拉框,再定位到下拉框下的選項,然后點擊兩次。
fixture`下拉框選取 `
    .page`file:///C:/Note/selenium_html/index.html`; test.only('下拉框選取 ', async t => { const phone = Selector('#moreSelect'); const phoneOption = phone.find('option'); await t .click(phone) .click(phoneOption.withText('oppe')); }); 
  • 三種警告框的處理setNativeDialogHandler(fn(type, text, url) [, options]):fu返回true 點擊確定,返回false點擊取消,返回文本則在prompt輸入文本,這個執行過程中就不會看到警告框彈出,直接處理掉。
fixture`警告框處理 ` .page`http://www.w3school.com.cn/tiy/t.asp?f=jseg_alert`; test('處理alert ', async t => { await t .switchToIframe("iframe[name='i']") // return true 表示點擊確定 .setNativeDialogHandler(() => true) .click('input[value="顯示警告框"]') .wait(10000); }); fixture`警告框處理 ` .page`http://www.w3school.com.cn/tiy/t.asp?f=jseg_prompt`; test.only('處理 提示框 ', async t => { await t .switchToIframe("iframe[name='i']") .setNativeDialogHandler((type, text, url) => { switch (type) { case 'confirm': switch (text) { //false 點擊 取消 case 'Press a button!': return false; // 返回 true 點擊確定 case 'You pressed Cancel!': return true; default: throw 'Unexpected confirm dialog!'; } case 'prompt': // 警告框填入值 hi vidor return 'Hi vidor'; case 'alert': throw '我是警告框!!'; } }) .click('input[value="顯示提示框"]') .wait(10000); }); 
  • 上傳文件setFilesToUpload(),清空上傳:clearUpload():
fixture`My fixture`
    .page`http://www.example.com/`; test('上傳圖片', async t => { await t .setFilesToUpload('#upload-input', [ './uploads/1.jpg', './uploads/2.jpg', './uploads/3.jpg' ]) // 清除上傳 .clearUpload('#upload-input') .click('#upload-button'); }); 

斷言

TestCafe自帶了較為齊全的斷言方法。斷言都是通過expect()開始;

import { Selector } from 'testcafe'; fixture `My fixture`; test('My test', async t => { // 斷言 通過CSS定位到的有3個元素,eql()表示相等,count表示定位元素個數 await t.expect(Selector('.className').count).eql(3); }); test('My test', async t => { // 斷言ok()表示為true,exists表示元素是否存在 await t.expect(Selector('#element').exists).ok(); }); 

更多APIdemo查看官方文檔:http://devexpress.github.io/testcafe/documentation/test-api/assertions/

特性

在介紹幾個TestCafe比較有意思的幾個地方。

執行速度

testcafe 支持測試執行的速度控制。 speed(x),x支持0.01到1之間,1則表示正常速度執行。

全局速度控制

可以通過控制台執行命令控制:
testcafe chrome xxxx.js --speed 0.1

控制某個test的執行速度

test("test setTestSpeed", I => { I.setTestSpeed(0.1); ...... }); 

控制某個步驟的執行速度

test("test setTestSpeed", I => { I.click("#kw").setTestSpeed(0.5); }); 

Chrome設備模擬

在啟動Chrome瀏覽器時,可以設定Chrome提供的模擬器。


 
image.png
testcafe "chrome:emulation:device=iphone x" xxx.js

設備模擬器更多參數查看:http://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/browsers/using-chrome-device-emulation.html

PageObject demo

大家都知道,做UI自動化測試,肯定得使用PO或者PF模式,下面簡單Demo個例子看看TestCafe 可以如何組織PO模式。
baiduPage.js

import {Selector, t as I} from 'testcafe' class baiduPage { baiduInput = Selector('#kw'); baiduButton = Selector('#su').withAttribute('value', '百度一下'); async searchBaidu(text) { await I .typeText(this.baiduInput, text, { // 清空 replace: true, }) .click(this.baiduButton) }; } export default baiduPage = new baiduPage(); 

baiduCases.js

import baiduPage from './baidu_page' fixture`baidu search`.page`https://www.baidu.com/`; test('po demo', async I => { await I.typeText(baiduPage.baiduInput, "test"); baiduPage.searchBaidu("testCafe"); await I.typeText(baiduPage.baiduInput,"居於之前的字符串空兩個字符中插入",{ caretPos:2 }) }); 

參數化/數據驅動

其實就是創建一個對象,用for ... of ... 循環遍歷

fixture`todoPage test cases`.page`http://todomvc.com/examples/react/#/`; const testCases = [ { todo: '123', }, { todo: '!@#$', } // 等等可能性的cases,這里隨便造兩個作為data driver ]; for (const todoText of testCases) { test('create todo list ' + todoText.todo, async t => { await todoPage.createTodoList(todoText.todo); await t.expect(todoPage.firstTodo.innerText).eql(todoText.todo); }); } 

運行方式Runner

TestCafe 可以通過命令行的方式來執行測試腳本,但是感覺實際過程中肯定不是很方便,特別如果運行時需要跟一堆參數的情況下,那么TestCafe 提供了Runner,更方便配置和運行。
如下配置,我需要被運行的Cases,錯誤自動截圖,並發,生成report,智能等待,執行速度,執行的瀏覽器等全部配到Runner里面,這樣我就不需要通過命令行運行,而且在項目中使用非常方便。

const createTestCase = require('testcafe'); const fs = require('fs'); let testcafe = null; createTestCase('localhost', 1337, 1338) .then(tc => { testcafe = tc; const runner = testcafe.createRunner(); const stream = fs.createWriteStream('report.json'); return runner // 需要運行的cases .src( [ '../demo/podemo/*.js', '../demo/setWindowsSize.js' ] ) // 設置需要執行的瀏覽器 .browsers([ 'chrome', 'firefox' ]) // 錯誤自動截圖 .screenshots( // 保存路徑 '../error/', true, // 保存路勁格式 '${DATE}_${TIME}/test-${TEST_INDEX}/${USERAGENT}/${FILE_INDEX}.png' ) // 生成report格式,根據需要安裝對應report模塊, // 詳細看:http://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/reporters.html .reporter('json', stream) // 並發 .concurrency(3) .run({ skipJsErrors: true, // 頁面js錯誤是否忽略,建議為true quarantineMode: true, // 隔離模式,可以理解為失敗重跑 selectorTimeout: 15000, // 設置頁面元素查找超時時間,智能等待 assertionTimeout: 7000, // 設置斷言超時時間 pageLoadTimeout: 30000, // 設置頁面加載超時時間 debugOnFail: true, // 失敗開啟調試模式 腳本編寫建議開啟 speed: 1 // 執行速度0.01 - 1 }); }).then(failedCount => { console.error('Failed Count:' + failedCount); testcafe.close(); }) .catch(err => { console.error(err); }); 

寫在最后

TestCafe 還有非常多有意思的東西可以去發掘,例如跟Jenkins等集成一類的。 個人demo了一些例子覺得是個非常值得推薦的 UI 自動化測試框架,特別是用JS編寫的在codecept,WebdriverIO我推薦TestCafe。 也許國內現在用的人不多,但相信是金子總會發光的。



作者:博客已遷移I米陽
鏈接:https://www.jianshu.com/p/94181abe5e9a
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM