1. 程式人生 > >vue-cli 腳手架基於Nightwatch的端到端測試環境的過程

vue-cli 腳手架基於Nightwatch的端到端測試環境的過程

物理 程序員 local muc useragent 業務流 bin ... 全局

不同公司和組織之間的測試效率迥異。在這個富交互和響應式處理隨處可見的時代,很多組織都使用敏捷的方式來開發應用,因此測試自動化也成為軟件項目的必備部分。測試自動化意味著使用軟件工具來反復運行項目中的測試,並為回歸測試提供反饋。

端到端測試又簡稱E2E(End-To-End test)測試,它不同於單元測試側重於檢驗函數的輸出結果,端到端測試將盡可能從用戶的視角,對真實系統的訪問行為進行仿真。對於Web應用來說,這意味著需要打開瀏覽器、加載頁面、運行JavaScript,以及進行與DOM交互等操作。簡言之,單元測試的功能只能確保單個組件的質量,無法測試具體的業務流程是否運作正常,而E2E卻正好與之相反,它是一個更高層次的面對組件與組件之間、用戶與真實環境之間的一種集成性測試 。

E2E測試的意義在於可以通過程序固化和仿真用戶操作,對於開發人員而言,基於E2E測試能極大地提高Web的開發效能,節約開發時間。

先來看看如果沒有E2E測試下的一次從開發到手工測試成功的過程:

技術分享圖片

這個過程還屬於簡化過的,還沒有包括在觀察結果時要打開瀏覽器的調試窗口觀看某些內部的運行變量或者網頁代碼結構。整個過程都是純人工操作,人工操作最大的問題是一個程序可能要調試好幾次,同樣的操作就要重復數遍。即使有嚴格的規定,程序員們大多都還是隨便地做“通過”式操作,尤其在輸入樣本數據時,絕大多數的程序員幾乎都是亂輸,出現得最多的就是各種隨意的數字或者是“aaa”、“asd”、“aws”這樣毫無意義的字符。以這種方式開發出來的程序在驗收時產品經理或者客戶會經常說一句話:“我上次試過是沒有問題的!”這樣的失誤歸根結底不在程序員本身,因為這是一種人性!一個人如果重復多次自己都覺得毫無意義的動作時,要不就逃避不做,如果不能逃避就會消極對待。

所以我們應該用更高效、更能彌補人性化缺陷和更有意義的辦法來處理,這就是E2E測試,先來看看如果使用E2E測試後的開發過程將會變成什麽:

技術分享圖片

從運行測試開始,所有的一切都是自動的!這就是最大的區別,還有更重要的一點是,當我們要寫出E2E測試時就需要對操作需求有深刻的理解,在這一過程中還有很大的機會對用戶的操作進行優化,從而提高用戶體驗。

Nightwatch

vue-cli的webpack模板也為我們準備了一個當下很流行的E2E測試框架——Nightwatch。

Nightwatch是一套新近問世的基於Node.js的驗收測試框架,使用Selenium WebDriver API以將Web應用測試自動化。它提供了簡單的語法,支持使用JavaScript和CSS選擇器來編寫運行在Selenium服務器上的端到端測試。

這個框架在配置好後的具體工作流程如下圖所示。

技術分享圖片

Nightwatch采用Fluent interface模式(https://en.wikipedia.org/wiki/Fluent_interface)來簡化端到端測試的編寫,語法非常簡潔易懂,正如以下代碼所示。

?
1 2 3 4 5 6 7 8 9 10 11 this.demoTestGoogle = function (browser) { browser .url(‘http://www.google.com‘) .waitForElementVisible(‘body‘, 1000) .setValue(‘input[type=text]‘, ‘nightwatch‘) .waitForElementVisible(‘button[name=btnG]‘, 1000) .click(‘button[name=btnG]‘) .pause(1000) .assert.containsText(‘#main‘, ‘The Night Watch‘) .end(); }

我們可以從Nightwatch網站找到當前提供特性的列表:

● 簡單但強大的語法。只需要使用JavaScript和CSS選擇器,開發者就能夠非常迅捷地撰寫測試。開發者也不必初始化其他對象和類,只需要編寫測試規範即可。

● 內建命令行測試運行器,允許開發者同時運行全部測試——分組或單個運行。

● 自動管理Selenium服務器;如果Selenium運行在另一臺機器上,那麽也可以禁用此特性。

● 支持持續集成:內建JUnit XML報表,因此開發者可以在構建過程中,將自己的測試與系統(例如Hudson或Teamcity等)集成。

● 使用CSS選擇器或Xpath,定位並驗證頁面中的元素或是執行命令。

● 易於擴展,便於開發者根據需要,實現與自己應用相關的命令。

配置 Nightwatch

要了解Nightwatch的配置和用法,與前文介紹Mocha一樣,應該先從工程結構入手。

工程結構

.
└── test
└── e2e
├── custom-assertions // 自定義斷言
│ └── elementCount.js
├── page-objects // 頁面對象文件夾
├── reports // 輸出報表文件夾
├── screenshots // 自動截屏
├── nightwatch.conf.js // nightwatch 運行配置
├── runner.js // 運行器
└── specs // 測試文件
└── test.spec.js

以上是vue-cli為我們自動創建的Nightwatch工程結構,specs是測試文件存放的文件夾,nightwatch.conf.js是Nightwatch的運行配置文件。其他的目錄將會在具體的章節逐一地進行講述。

基本配置

Nightwatch的配置項都集中在nightwatch.conf.js中,其實這個配置也可以是一個JSON格式,采用JSON格式只需要簡單地對配置項寫入一些常量即可。但使用模塊的方式進行配置可以執行一些額外的配置代碼,這樣則顯得更為靈活。以下是我調整過的nightwatch.conf.js文件內容:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 require(‘babel-register‘); var config = require(‘../../config‘); var seleniumServer = require(‘selenium-server‘); var phantomjs = require(‘phantomjs-prebuilt‘); module.exports = { "src_folders": ["test/e2e/specs"], "output_folder": "test/e2e/reports", "custom_assertions_path": ["test/e2e/custom-assertions"], "page_objects_path": "test/e2e/page-objects", "selenium": { "start_process": true, "server_path": seleniumServer.path, "port": 4444, "cli_args": { "webdriver.chrome.driver": require(‘chromedriver‘).path } }, "test_settings": { "default": { "selenium_port": 4444, "selenium_host": "localhost", "silent": true, launch_url:"http://localhost:" + (process.env.PORT || config.dev.port), "globals": { } }, "chrome": { "desiredCapabilities": { "browserName": "chrome", "javascriptEnabled": true, "acceptSslCerts": true } }, "firefox": { "desiredCapabilities": { "browserName": "firefox", "javascriptEnabled": true, "acceptSslCerts": true } } } }

Nightwatch的配置分為以下三類:

● 基本配置;

● Selenium配置;

● 測試環境配置。

在配置模塊中的所有根元素配置項都屬於基本配置,用於控制Nightwatch的全局性運行的需要。下表為Nightwatch的基本配置項的詳細說明。

技術分享圖片

Selenium 配置

Selenium是一組軟件工具集,每一個工具都有不同的方法來支持測試自動化。大多數使用Selenium的QA工程師只關註一兩個最能滿足他們項目需求的工具。然而,學習所有的工具你將有更多選擇來解決不同類型的測試自動化問題。這一整套工具具備豐富的測試功能,很好地契合了測試各種類型的網站應用的需要。這些操作非常靈活,有多種選擇來定位UI元素,同時將預期的測試結果和實際的行為進行比較。Selenium一個最關鍵的特性是支持在多瀏覽器平臺上進行測試。

Selenium誕生於2004年,當在ThoughtWorks工作的Jason Huggins在測試一個內部應 用時,作為一個聰明的家夥,他意識到相對於每次改動都需要手工進行測試,他的時間應該用得更有價值。他開發了一個可以驅動頁面進行交互的JavaScript庫,能讓多瀏覽器自動返回測試結果。那個庫最終變成了Selenium的核心,它是Selenium RC(遠程控制)和Selenium IDE所有功能的基礎。Selenium RC是開拓性的,因為沒有其他產品能讓你使用自己喜歡的語言來控制瀏覽器。

Selenium是一個龐大的工具,所以它也有自己的缺點。由於它使用了基於JavaScript的自動化引擎,而瀏覽器對JavaScript又有很多安全限制,有些事情就難以實現。更糟糕的是,網站應用正變得越來越強大,它們使用了新瀏覽器提供的各種特性,都使得這些限制讓人痛苦不堪。在2006年,一名Google的工程師Simon Stewart開始基於這個項目進行開發,這個項目被命名為WebDriver。此時,Google早已是Selenium的重度用戶,但是測試工程師們不得不繞過它的限制。Simon需要一款能通過瀏覽器和操作系統的本地方法直接和瀏覽器進行通話的測試工具,來解決JavaScript環境沙箱的問題。WebDriver項目的目標就是要解決Selenium的痛點。

Selenium 1 (又叫Selenium RC或Remote Control)在很長一段時間內,Selenium RC都是最主要的Selenium項目,直到WebDriver和Selenium合並而產生了最新且最強大的Selenium 2。Seleinum 1仍然被活躍地支持著(更多是維護),並且提供一些Selenium 2短時間內可能不會支持的特性,包括對多種語言的支持(Java、JavaScript、Ruby、PHP、Python、Perl和C#)和對大多數瀏覽器的支持。

Selenium 2 (又叫Selenium WebDriver)代表了這個項目未來的方向,也是最新被添加到Selenium工具集中的。這個全新的自動化工具提供了很多了不起的特性,包括更內聚和面向對象的API,並且解決了舊版本限制。Selenium和WebDriver的作者都贊同兩者各具優勢,而兩者的合並使得這個自動化工具更加強健。Selenium 2.0正是於此的產品。它支持WebDriver API及其底層技術,同時也在WebDriver API底下通過Selenium 1技術為移植測試代碼提供極大的靈活性。此外,為了向後兼容,Selenium 2仍然使用Selenium 1的Selenium RC接口。

你可以到http://selenium-release.storage.googleapis.com/index.html下載Selenium的各個穩定版本。

在Vue項目中如果使用vue-cli,那麽Nightwatch將不需要進行任何的附加配置,否則你需要在命令行內安裝Selenium的包裝類庫:

$ npm i selenium-server -D

Nightwatch能引導Selenium的啟動,實際上我們並沒有必要去修改Selenium服務器的默認運行配置,在nightwatch.conf.js配置文件中只需要聲明Selenium服務器的二進制執行 文件的具體路徑即可,這個可以從selenium-server包提供的Selenium包裝對象的path屬性中獲取,而無須
將本機的物理路徑寫死到配置文件內。

?
1 2 3 4 5 6 7 8 9 10 11 12 var seleniumServer = require(‘selenium-server‘); module.exports= { "selenium": { "start_process": true, "server_path": seleniumServer.path, "port": 4444, "cli_args": { "webdriver.chrome.driver": require(‘chromedriver‘).path } }, // ... 省略 }

以下是Selenium的詳細配置項說明:

技術分享圖片

cli_args 的配置

● webdriver.firefox.profile:Selenium默認為每個會話創建一個獨立的Firefox配置方案。如果你希望使用新的驅動配置可以在此進行聲明。

● webdriver.chrome.driver:Nightwatch同樣可以使用Chrome瀏覽器加載測試,當然你要先下載一個ChromeDriver的二進制運行庫對此進行支持。此配置項用於指明ChromeDriver的安裝位置。除此之外,還需要在test_settings配置內使用desiredCapabilities對象為Chrome建立配置方案。

● webdriver.ie.driver:Nightwatch也支持IE,其作用與用法與Chrome相同,此處則不過多贅述。

測試環境配置

test_settings內的項目將應用於所有的測試實例,在E2E測試中我們可以通過Nightwatch提供的默認實例對象browser獲取這些配置值,vue-cli為我們創建了default、firefox和chrome三個環境配置項,default配置是應用於所有環境的基礎配置選項,其他的配置項會自動覆蓋與default相同的配置值。

firefox和chrome這兩個配置項是對兩種瀏覽器的驅動進行描述和配置。對於其他語言或框架而言它們也是常客,但由於性能太低,在實戰中通常只是個擺設,下文中我將會介紹一種實戰效率更高的無頭瀏覽器PhantomJS,對其取而代之。

不要被vue-cli創建默認配置所迷惑,test_settings並不單單只是對瀏覽器的一些基本運行參數的配置,它正確的用法是對E2E測試環境的配置。單元測試只能運行於開發環境內,而E2E卻可以運行於本地環境與網絡環境,更準確地說是開發環境與生產環境。所以這個配置項可以用以下的方式進行設置:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 "test_settings": { "default": { "selenium_port": 4444, "selenium_host": "localhost", "silent": true, launch_url:"http://localhost:" + (process.env.PORT || config.dev.port), "globals": {} }, "dev": { "desiredCapabilities": { "browserName": "chrome", "javascriptEnabled": true, "acceptSslCerts": true } }, "production": { "launch_url":"http://www.your-domain.com" "desiredCapabilities": { "browserName": "firefox", "javascriptEnabled": true, "acceptSslCerts": true } } }

雖然與原有的配置只是在用詞上做了一點點改變,但用詞的改變將會徹底地改變我們對其的認知與思路!

下表是測試環境配置項的詳細說明:

技術分享圖片

執行 E2E 測試

vue-cli已經在package.json中配置了運行測試的指令:

$ npm run e2e

這個指令是默認啟用Chrome運行環境的,如果指定運行環境可使用--env選項:

$ npm run e2e --env

使用無頭瀏覽器 PhantomJS

vue-cli webpack腳手架模板非常好用,它將環境的復雜性降低了很多,但是卻沒有很好地詮釋它裏面采用的每個模塊的理由和功能,以及它們的使用特點。這對於入門者來說確實是將門檻降到最低點,但從工程化開發的角度來說,只知道有這些環境或者工具的存在是遠遠不夠的,在Nightwatch中就埋了一個這樣的坑。

我們的開發環境在配置Mocha和Karma時就已經安裝了PhantomJS,但如果你細讀Nightwatch的默認配置會驚奇地發現根本沒有采用PhantomJS,只是配置了Chrome和Firefox!問題何在?一個字:慢!

我曾用一臺2013年版標準配置(i5CPU、8GB內存、1TB HDD硬盤)的iMac跑本書下一章中的示例程序,運行一次的實際時間是15秒左右!僅僅一次就得15秒,那可以想象我們開發一個場景最少要做多少次的運行?Chrome的啟動是很慢的,我們做E2E這種自動化測試如果用真實瀏覽器的話

只能將性能拖下來,生命不能耗費在毫無意義的等待中!所以我們才會選擇PhantomJS!沒有默認配置PhantomJS作為主瀏覽器是這個環境的最大敗筆。

辦法總比問題多,所以如果沒有,我們還可以自己動手來配置,其實方法也很簡單。打開nightwatch.conf.js,在test_settings配置段的下方加入以下的內容:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 "test_settings": { "default": { // ... } }, "phantom":{ "desiredCapabilities": { "browserName": "phantomjs", "javascriptEnabled": true, "acceptSslCerts": true, "phantomjs.page.settings.userAgent" : "Mozilla/5.0 (Macintosh; Intel MacOS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", "phantomjs.binary.path":"node_modules/phantomjs-prebuilt/bin/phantomjs" } }

Nightwatch是通過Selenium加載一個GhostDriver來引導PhantomJS瀏覽器的,上面的內容就相當於告訴Selenium加載一個GhostDriver,可執行程序則指向npm上安裝的phantomjs-prebuilt包,再通過這個包來引導安裝在本機上的PhantomJS啟動。

按上文這樣來引用PhantomJS的二進制程序的地址非常難看,還有原生配置中的Selenium執行程序地址也是一樣的,這裏介紹一個更DRY的方法來處理這些路徑:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var seleniumServer = require(‘selenium-server‘); var phantomjs = require(‘phantomjs-prebuilt‘); module.exports = { // ...省略 "selenium": { // ... 省略 "server_path": seleniumServer.path, }, "test_settings": { // ... 省略 "phantom": { "desiredCapabilities": { // ... 省略 "phantomjs.binary.path": phantomjs.path } } // ... 省略 } }

做完這個簡單的優化後就可以打開runner.js文件找到:

?
1 2 3 if (opts.indexOf(‘--env‘) === -1) { opts = opts.concat([‘--env‘, ‘chrome‘]) }

 將chrome改為phantom就行了:

?
1 2 3 if (opts.indexOf(‘--env‘) === -1) { opts = opts.concat([‘--env‘, ‘phantom‘]) }

重新加載測試程序,在同一臺iMac上的運行速度直接降到了5秒,測試運行速度提升了3倍!如果你有配置更好的機器,將硬盤換成SSD之後會有更驚人的速度。

Nightwatch 與 Cucumber

如果你正在開發的項目的業務復雜性不大,可以直接使用Nightwatch推薦的鏈式調用寫法。但是當這種做法真正應用在業務流程較多,或者業務操作相對復雜的應用場景時,你會覺得總有寫不完的E2E測試,因為這麽做E2E測試是沒有辦法一次性覆蓋所有需求的!

E2E測試其實是行為式驅動開發的實現手法,如果跳過了行為式驅動開發的分析部分直接編寫E2E,其結果只能是寫出一堆嚴重碎片化的測試場景,甚至會出現很多根本不應該出現的操作。

幸好Nightwatch具有很好的擴展性與兼容性,能集成最正統的BDD測試框架Cucumber(https://cucumber.io/)。Cucumber是原生於Ruby世界的BDD框架,但它也有很多的語言實現版本,我們可以安裝一套專門為Nightwatch編寫的Cucumber版本——nightwatch-cucumber(https://github.com/mucsi96/nightwatch-cucumber)。本章只介紹關於環境與工具的配置,而關於如何來應用BDD,內容已經超出了本書的知識範圍,如果有興趣的話可以參考《攀登架構之巔》一書中行為式驅動開發的章節內容。

$ npm i nightwatch-cucumber -D

然後在~/test/e2e/nightwatch.conf.js文件中加入對Cucumber的配置:

?
1 2 3 4 5 6 7 8 9 10 // ... 省略 require(‘babel-register‘); require(‘nightwatch-cucumber‘)({ nightwatchClientAsParameter: true, featureFiles: [‘test/e2e/features‘], stepDefinitions: [‘test/e2e/features/step_definitions‘], jsonReport: ‘test/e2e/reports/cucumber.json‘, htmlReport: ‘test/e2e/reports/cucumber.html‘, openReport: false });

總結

vue-cli 腳手架基於Nightwatch的端到端測試環境的過程,希望對大家有所幫助

vue-cli 腳手架基於Nightwatch的端到端測試環境的過程