SauceLabs selenium testing with selenium-webdriver

selenium 是用來做瀏覽器測試的工具,讓你可以安排一個流程在真實瀏覽器上運行來測試結果是否如預期,已經被大量用在 Web 的測試上,這已經許多年,也有許多教學了。

而在 selenium 的測試上,最方便的是能跨瀏覽器測試,但是最麻煩的是你要安排有很多瀏覽器的機器(或虛擬機器),並把環境部屬好,供 selenuim 運行。

而 saucelab 是一個雲端的測試平台,就是用來解決這個問題,他提供了隨時供你取用的運算資源,讓你隨時可以模擬各種平台不同版本的作業系統與瀏覽器,他是一個付費的服務,但是有免費試用的額度可以玩玩看。

這篇文章紀錄從頭到尾透過 nodejs 在本機建立建立一個 selenuim 的測試環境,最後在透過 saucelab 來測試其他作業系統與瀏覽器。

需求

Selenium Server 2.44.0.jar:控制介面,可以透過呼叫他來控制隱藏在其背後不同的瀏覽器。

Chrome WebDriver:實際要連結被測試瀏覽器的驅動程式稱為 web driver,每個不同瀏覽器有他自己的 driver 這個範例是用 chrome 為例子。

測試

# with chrome driver
$ java -jar selenium-server-standalone-2.44.0.jar -Dwebdriver.chrome.driver=./chromedriver
# with ie driver
$ java -jar selenium-server-standalone-2.44.0.jar -Dwebdriver.ie.driver=C:\IEDriverServer.exe

啟動 Server 並指定 chrome.webdriver 的路徑,接著挑你想要寫測試的語言,在這邊例子是 nodejs,先安裝相依的套件。

$ npm install selenium-webdriver

跑個簡單的範例,連到 google 搜尋我的網域,測試結果是不是我的網誌。

selenium-webdriver 的文件 不是很好懂,因為他本身帶有流程控制的功能,讓你可以在非同步的 js 也可以照著流程循序執行,來進行測試,但是寫起來就會不太直覺。

因為所有程式執行的當下都沒有做動作,而是像是針對一個 queue 下指令,接著 selenium 就會按照指令一步的執行你的動作,所以要取得當下的狀態都要在 callback 裡面做。

var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();

driver.get('http://www.google.com.tw');
driver.findElement(webdriver.By.name('q')).sendKeys('mlwmlw.org');
driver.findElement(webdriver.By.name('btnK')).click();
driver.wait(function() {
  return driver.isElementPresent(webdriver.By.css("h3")).then(function(presented) {
    return presented;
  });
}, 3000)
driver.findElement(webdriver.By.css("h3")).getText().then(function(text) {
  if(/阿喵就像家/.test(text)) {
    console.log('Success');
  }
  else {
    console.log('Failed');
  }
});
driver.quit();

如果你要換成透過 saucelab 測試,只要把你的 username 跟 accesskey 設定到環境變數,並且把範例裡面 withCapabilities 換成你想要的瀏覽器與作業系統,工作就會被丟到 saucelab 去執行了,例如:

 $ export SAUCE_USERNAME=mlwmlw
 $ export SAUCE_ACCESS_KEY=growlmwlm
var sauce = 'http://ondemand.saucelabs.com:80/wd/hub';
var driver = new webdriver.Builder().
usingServer(sauce).
withCapabilities({
   browserName: 'internet explorer',
   platform: 'Windows 7',
   version: '8',
   username: process.env.SAUCE_USERNAME,
   accessKey: process.env.SAUCE_ACCESS_KEY
}).
build()

接著去 sauceLab 的工作裡面看,甚至能夠看 live 播出測試的過程,在執行完或失敗時,也可以直接接著操作模擬的介面,saucelab 也有提供純手動的操作可以測試。

IE 醬油

用 iedriver 測試的時候會踩到一些地雷,如果用太多 css selector,根據這篇文章所述,在 IE6,7 因為沒有 querySelector,所以會 selenium 會載入 sizzle 來代替,但在 IE8 以後會用原生的 selector 來實作,聽起來很理想,漸進式的支援,但是..,IE8 那半殘的 selector,沒辦法選擇第幾個元素(nth),所以只能用 xpath 之類的方法繞過了..。

這裡有個 IE8 選元素的方法可以參考: http://automatictester.wordpress.com/2014/05/04/ie8-and-nth-child-css-selector/

例如要選按某個下拉式選單的第 3 個選項好了,從 css 改寫成 xpath


// css selector
driver.findElement(webdriver.By.css("select#dropdown option:nth-child(3)"));
// xpath selector
driver.findElement(webdriver.By.xpath("//select[@id='dropdown']/option[3]"));

同場加映 Phantomjs

如果要在伺服器上測試沒有 GUI 的話,可以用 phantomjs 這個不需要桌面的無頭瀏覽器,只要裝起來他內建就有支援 selenium 的 driver(ghost driver)。只是不像 IE driver 跟 chrome driver 可以榜在 server 上由 server 自動啟動,phantomjs 要自己手動先啟動。

 $ npm install phantomjs -g
 # 跑 hub 模式
 $ java -jar selenium-server-standalone-2.44.0.jar -role hub
 # 另開一個 terminal 啟動 phantomjs 連接到 hub
 $ phantomjs --webdriver=8080 --webdriver-selenium-grid-hub=http://127.0.0.1:4444

啟動時指定 phantomjs 就能跑哩。

withCapabilities(webdriver.Capabilities.phantomjs())

nightwatch

logo-nightwatch
實際寫了一大堆測試以後,好像只是在叫瀏覽器做事情,程式很雜,很難分類去知道哪個步驟成功哪個步驟失敗,只能最後再從 log 去看結果,程式又不好維護。

所以就找到了可以做單元測試的 nodejs library,nightwatch.js,他可以幫忙把流程切割成好幾個單元,而且提供檢查值的函式,所以可以比較有組織的進行測試,且包覆了一層 selenium 的 api,改善了很多呼叫的介面,例如把等待某個元素這個功能包成一個函式,經常使用到,原本的寫法又笨又長,所以改完以後程式流程變得比較簡潔又易懂。

例如上述的範例改成 nightwatch 就變成如下,是不是簡化蠻多,主要改善應該是比較不需要寫到 callback 了。

module.exports = {
  "test" : function (client) {
    client
      .url("http://www.google.com")
      .waitForElementVisible("body", 1000)
      .assert.visible("input[type=text]")
      .setValue("input[name=q]", "mlwmlw.org")
      .waitForElementVisible("button[name=btnK]", 1000)
      .click("button[name=btnK]")
      .pause(1000)
      .assert.containsText("h3", "阿喵就像家");
  },
  "test2": function (client) {
      client
        .assert.containsText("h3", "喵喵的筆記")
        .end();
  }
};

上述測試的程式放到 tests 資料夾下,並且把設定檔設好,再安裝 nightwatch 以後,讓 nightwatch 去讀 nightwatch.json 指定用 saucelabs 來跑,不然也能指定不同的 environment 來跑在指定的 selenium server 上。

{
	"src_folders" : ["tests"],
	"output_folder" : "tests/reports",
	"test_settings" : {
		"default" : {
			"selenium_host"  : "ondemand.saucelabs.com",
			"username": "${SAUCE_USERNAME}",
			"access_key": "${SAUCE_ACCESS_KEY}"
		},
		"ie": {
			"desiredCapabilities": {
			  "browserName": "internet explorer",
				"browserVersion" : "8.0",
				"platform": "WINDOWS 7",
				"javascriptEnabled": true,
				"acceptSslCerts": true
			}
		},
		"chrome" : {
			"desiredCapabilities": {
			  "browserName": "chrome",
			  "platform": "WINDOWS 7",
			  "javascriptEnabled": true,
			  "acceptSslCerts": true
			}
		},
		"firefox": {
			"desiredCapabilities": {
				"browserName": "firefox",
				"platform": "WINDOWS 7",
				"javascriptEnabled": true,
				"acceptSslCerts": true
			}
		}
	}
}
 $ npm install nightwatch -g 
 $ nightwatch -e ie,chrome,firefox --test=test.js

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *