上一篇解釋了虛擬碼的概念,這次直接進入撰寫測試的方法。當然,需要一點工具來輔助我們,這裡我們使用 nightwatch.js 來當作測試的框架。
如果不是使用 nightwatch.js 的人,可以左轉沒關係。
環境
萬事起頭難,建立環境這件事情最難! 雖然我們使用 nightwatch.js 來當做測試框架,但是我們還是需要具備一些基礎知識,好方便我們操作。首先,我們需要的有,
- 可以運行 NodeJS 的環境
- 可能需要安裝 Java SDK
- selenium-server-standalone 獨立執行檔 (*1)
- Firefox driver
接著,我們這邊可以來建立一個相對簡易的測試環境,我們需要的目錄與檔案結構如下,
specs
bin
package.json
nightwatch.conf.js
runner.js
我們可以先下載上述的獨立執行檔,把他放到 bin
目錄底下備用。另外,如果你需要使用 Firefox 來運行測試環境,也請把 Firefox driver 放到 bin
目錄底下。
底下的設定檔都可以照抄沒關係,更詳細的設定可以察看 nightwatch.js,或是上網 Google 也可以(欸
首先 package.json
會寫入我們所需要安裝的一些套件,
{
"scripts": {
"test": "node runner.js"
},
"dependencies": {
"babel-register": "^6.22.0",
"chromedriver": "^2.27.2",
"cross-env": "^3.1.4",
"cross-spawn": "^5.0.1",
"lodash": "^4.17.4",
"mocha": "^3.2.0",
"nightwatch": "^0.9.12",
"selenium-server": "^3.0.1"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
接著 runner.js
提供啟動測試的程序,
process.env.NODE_ENV = 'staging'
var opts = process.argv.slice(2)
if (opts.indexOf('--config') === -1) {
opts = opts.concat(['--config', 'nightwatch.conf.js'])
}
if (opts.indexOf('--env') === -1) {
opts = opts.concat(['--env', 'chrome'])
}
var spawn = require('cross-spawn')
var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
runner.on('exit', function (code) {
process.exit(code)
})
runner.on('error', function (err) {
throw err
})
暫停,我們先在終端機執行一些套件的安裝,
npm run install
安裝好之後,我們來編輯一下 nightwatch.conf.js
這個設定檔,可以參考官方的 簡單範例 來進行一些修改,
{
"src_folders" : ["specs"],
"output_folder" : "reports",
"custom_commands_path" : "",
"custom_assertions_path" : "",
"page_objects_path" : "",
"globals_path" : "",
"selenium" : {
"start_process" : true,
// "server_path" : require('selenium-server').path,
"server_path" : "./bin/selenium-server-standalone-3.8.1.jar",
"log_path" : "",
"port" : 4444,
"cli_args" : {
"webdriver.chrome.driver" : require('chromedriver').path,
"webdriver.gecko.driver" : "./bin/geckodriver"
}
},
"test_settings" : {
"default" : {
"launch_url" : "http://localhost",
"selenium_port" : 4444,
"selenium_host" : "localhost",
"silent": true,
"screenshots" : {
"enabled" : false,
"path" : ""
}
},
"chrome" : {
"desiredCapabilities": {
"browserName": "chrome"
}
},
"firefox" : {
"desiredCapabilities": {
"browserName": "firefox"
}
}
}
}
然後我們就能進入 specs
當中開始寫測試了。
*1 獨立執行檔僅只是官方建議,其實也可以使用 package.json
當中的 selenium-server
套件來執行(例如上述註解掉的那一段)。
開始寫測試之前
畢竟是叫做 End-to-End 測試,所以必須還是要有一些基本的能力,
- 理解 HTML / DOM
- 理解 CSS 選擇器
- 理解 JavaScript
- 會一些簡易的 Chrome DevTools 操作
- 翻閱大量的 nightwatch.js 的 API 官方文件
所以,在這個大前提之下,你必須對於 DOM 有一定的認知,才能知道你要怎麼做。我們先回到上一次所說的虛擬碼,要把虛擬碼轉換成測試用的程式碼之前,先思考一下該怎麼認識 畫面上的東西。
這次就不說販賣機了,就說 Google 的首頁好了。假設我們有一段虛擬碼是這個樣子的,
- 打開 https://google.com
- 輸入搜尋的關鍵字「閃光洽」
- 按下「搜尋」按鈕
- 找到第一筆搜尋結果
- 第一筆搜尋結果要包含「閃光洽」的字樣
以上的動作都是透過滑鼠與鍵盤,在你的瀏覽器中操作的步驟。那麼,我們該怎麼透過測試方法,自動幫我操作?我們可以理解的方式是,
叫同事幫我操作(不是
由於網頁是由一大堆 HTML 標籤所組成,他組合出來的叫做 DOM (文件物件模型,Document Object Model)。所以,我們需要的能力是 查找 DOM 來找到我們想要的 物件。
以上述的例子來說,輸入關鍵字 這件事情,就會有一下的步驟,
- 先在 DOM 找到 可以輸入關鍵字 的地方
- 然後輸入關鍵字「閃光洽」
那麼,我們要怎麼找到 可以輸入關鍵字 的地方?首先,你需要複習一點 CSS 選擇器,例如,
#E
ID 選擇器.E
類別選擇器E F
子嗣選擇器[E="F"]
屬性選擇器
那麼,我們可以利用 Chrome DevTools 來簡易的驗證選擇器,與確認我們是否有 選到 我們想要選的東西。我們分成幾個步驟來說明 DevTools 的操作,
- 打開 Chrome 後,打開 https://google.com
- 在搜尋的輸入框的地方,按下滑鼠右鍵,點選「檢視」
- 這個時候會開出 DevTools 的工具,會出現剛剛你「檢視」的元件
- 我們可以在上面那個區塊任一點一下,按下
Command + F
,會出現搜尋框
- 這個地方我們可以用來驗證我們的選擇器,是否可以選我們想要的元件,例如說,我們輸入
input[type="text"]
- 就這麼剛好選到我們要的東西了呢(啾咪
接著我們先略過輸入關鍵字這件事情,假設我們輸入好了,要去按搜尋的按鈕。所以,我們就要找到那個按鈕。我們一樣可以使用 DevTools 來找到那顆按鈕,一樣是在按鈕上「檢視」,來察看那顆按鈕有什麼樣的屬性可以供我們使用。
以上,我們使用了 CSS 選擇器,並透過 DevTools 來輔助我們選到想要的元件。這樣,對於選擇元件這件事情,在這裡就有一個基本的認識。會選擇元件之後,我們就可以來寫第一次的簡單測試了。
nightwatch.js 簡易測試
在 specs
資料夾中,我們可以建立一個檔案叫做 test.js
用來寫我們的第一個測試。這個檔案有一個規則,就是必須被包含在 module.exports = { }
裡面,至於為什麼?不要問,很可怕!
module.exports = {
'我的第一個測試': function (browser) {
browser
.url('https://google.com')
.waitForElementVisible('input[type="text"]', 1000)
.setValue('input[type="text"]', '閃光洽')
.click('input[jsaction="sf.chk"]')
.pause(1000)
.waitForElementVisible('#rso .g:first-child', 1000)
.assert.containsText('#rso .g:first-child', '閃光洽')
.end();
}
}
我們逐步來說明上述的測試代碼做了什麼事情,
browser
在 nightwatch.js 當中,會回傳一個參數,這個參數就是測試用的瀏覽器物件,所有的動作都會基於這個瀏覽器物件來做操作。.url('https://google.com')
請這個瀏覽器打開https://google.com
這個網址.waitForElementVisible
是 nightwatch.js 提供的一個方法,用意是,等待你指定的選擇器input[type="text"]
所選到的 元件 出現在畫面上,最久等待 1000 毫秒。.setValue
顧名思義,是將某個數值填入選擇器,通常會用於input
類型的標籤,這個方法可以指定一個值給這個元件。例如我們要輸入搜尋的關鍵字,就會使用這個方法。.click
模擬滑鼠點擊選擇器input[jsaction="sf.chk"]
所選到的元件 (*2).pause
暫停操作 1000 毫秒。為何會需要暫停?因為送出關鍵字之後,要等待回應,等待的時間我們就可以先暫停操作。.assert.containsText
這是屬於assert
的一組方法,用意是檢查指定選擇器#rso .g:first-child
的 所有 文字內容,是否有包含你所指定的文字。.end()
測試做完了,關閉測試用的瀏覽器。
以上是簡易的測試步驟,所有的相關文件後續會有比較詳細的介紹。當然測試當中可能還是會遇到一些 nightwatch.js 奇怪的雷,我會慢慢找時間分享給大家。
*2 點擊這個動作有比較特別的條件,之後會另外有篇幅來講講這個雷。
小結
不覺得,用 nightwatch.js 來搶票好像不錯嗎(欸