搭建本身的前端自動化測試腳手架(三)

上一篇:搭建本身的前端自動化測試腳手架(二)
By LancerComet at 23:47, 2016.07.22. 歡迎轉載,轉載時還請保留做者署名。前端

這是最後一章了!(・∀・)
以前咱們配置好了咱們的腳手架工具,如今能夠編寫測試用例了!git

開始編寫測試用例

建立目錄存放測試用例

在項目根目錄新建一個名爲 "tests" 的目錄,而後這裏就用來存放咱們即將編寫的測試用例文件。
那麼這個文件夾能不能指向到其餘地方去呢?固然能夠,不過要修改一個小地方。github

還記得 " nightwatch.json " 文件麼?打開看看,第一項是否是叫 src_folders,而後值爲 ["tests"]
我相信您已經懂了,這裏就是定義測試用例存放目錄的地方,而後改爲本身想要的目錄吧!npm

您能夠在目錄中存放多個測試用例文件,且命名隨意,Nightwatch 將讀取目錄中全部的 JS 文件,若是符合測試用例格式,將會自動執行。json

編寫一個簡單的測試用例

在 "tests" 目錄中創建一個測試用例文件 "demo.js",而後咱們來寫一個沒什麼用的小 demo!segmentfault

這個 Demo 將打開 Bing,搜索 "what is microsoft",而後保存成截圖後退出。api

OK,打開 "demo.js",添加如下內容:瀏覽器

module.exports = {
  'Find the answer.': function (client) {
    // TODO...
  }
}

module.exports 導出一個對象,對象的 Key 即爲測試用例名稱,您能夠編寫多個測試用例,Nightwatch 將依次執行。cookie

您能夠在測試用例中導入其餘模塊並直接使用在測試邏輯中,這也是比 Phantom.JS 優秀的地方。架構

先寫到這裏,您可能會對 cilent 感到陌生,因此仍是要簡單介紹一下。

client 是代碼運行時 Nightwatch 提供的對象,全部對瀏覽器進行的操做都將使用此對象調取,好比 client.click("CSS Selector")client.getCookie(function () {...}),咱們第一章說過的 "能夠簡單理解爲 Selenium 的控制軟件" 就是經過它體現的喔!

client 的全部 API 詳情見 這裏

大體瞭解這東西的意思以後,就能夠接着完善測試邏輯了:

module.exports = {
  'Find the answer.': function (client) {
    // 定義 Bing 頁面中的節點.
    const searchInput = '#sb_form_q'
    const searchBtn = '#sb_form_go'
    const question = 'what is microsoft'

    // 啓動瀏覽器並打開 bing.com.
    client.url('http://bing.com').maximizeWindow()

    // 確保 "body" 和輸入框可使用.
    client.expect.element('body').to.be.present
    client.expect.element(searchInput).to.be.visible
    client.pause(2000)  // 稍等兩秒.

    // 輸入 "what is microsoft" 而後搜索.
    client.setValue(searchInput, question)
    client.click(searchBtn)
    client.pause(2000)

    // 截一張圖而後保存到 "reports/answer.png". 
    client.expect.element('body').to.be.present
    client.saveScreenshot('reports/answers.png')
    client.end()
  }
}

來關注一下 expect ,是否是看起來很像天然語言?這些語句就是測試結果的驗證語句,就是咱們但願獲得的結果。好比 client.expect.element('body').to.be.present.before(3000),意思就是 "但願 body 元素能在 3000 毫秒內初始化完畢"。

Nightwatch 支持 BDD-Style 與 Assert 斷言兩種風格,文檔可見 這裏

關於 Assert、BDD、TDD 的更多內容請參照其餘文章。

是否是確實沒什麼用?畢竟是個簡單的 Demo 而已,哈哈。
那麼添加一個稍微複雜點的測試用例。

編寫另外一個簡單的測試用例

這個 demo 將打開 Bilibili 直播 ,而後執行:

  • 打開首頁並等待加載完畢;

  • 檢查登錄按鈕是否存在;

  • 點擊登錄按鈕;

  • 填寫用戶名與密碼;

  • 點擊登錄;

  • 等待頁面加載;

  • 經過 Cookie 檢查是否已登錄;

  • 確保登錄後的用戶導航面板存在;

  • 鼠標移至頭像處打開導航面板;

  • 點擊退出登錄;

  • 等待頁面刷新後檢查 Cookie 是否已退出登錄;

  • 結束測試。

其實就是第一章的那個 Demo 圖乾的事情了 (・∀・)
這個 demo 再也不囉嗦,直接放出代碼:

// Account setting.
const accountConfig = {
  username: 'USERNAME',
  password: 'PASSWORD',
  uid: '10000'
}

module.exports = {
  'Bilibili Live Login Test': function (client) {
    client.url('http://live.bilibili.com').maximizeWindow()

    // Page Init.
    client.expect.element('body').to.be.present.before(3000)
    client.expect.element('.top-nav-login-btn.last').to.be.visible

    // Login.
    client.click('.top-nav-login-btn.last')
    client.waitForElementVisible('#bilibili-quick-login', 2000)
    client.frame(0)
    client.pause(2000)
    client.setValue('#login-username', accountConfig.username)
    client.setValue('#login-passwd', accountConfig.password)
    client.click('#login-submit')

    // Wait and check page has been reloaded.
    client.frameParent()
    client.pause(4000)
    client.expect.element('body').to.be.present.before(3000)

    // Check cookies to ensure we are signed in.
    client.getCookies(function (result) {
      result.value.forEach((value, index, array) => {
        if (value.name === 'DedeUserID') client.assert.equal(parseInt(value.value, 10), accountConfig.uid)
      })
    })

    // Move to User Avatar.
    client.expect.element('.user-avatar-link').to.be.visible
    client.moveToElement('.user-avatar-link', 5, 5)
    client.pause(800)
    client.expect.element('#top-nav-user-panel').to.be.visible

    // Logout.
    client.click('#top-nav-logout-link')
    client.pause(5000)
    client.expect.element('body').to.be.present.before(3000)

    // Check cookies again to ensure we are off.
    client.getCookies(function (result) {
      var logout = true
      result.value.forEach((value, index, array) => {
        if (value.name === 'LIVE_LOGIN_DATA') logout = false
      })
      client.assert.equal(logout, true)
    })

    client.pause(1000)
    client.end()
  }
}

您能夠新建一個文件,或者在以前的文件中繼續編寫。

運行測試用例

回到項目根目錄,執行 npm start,而後就能夠看到瀏覽器本身測試了!
運行效果以下:
自動化測試

測試運行完畢以後,測試結果將打印在終端裏,同時會生成到 reports 文件夾中。

您能夠在 nightwatch.json 中修改 "output_folder" 來更換報告生成目錄。

須要注意的地方

您可能在使用中會遇到例如 「明明看到節點缺獲取不到」、「鼠標功能好像時好時壞」 等問題,在此給您一些建議:

  • 因爲如今不少網站使用諸如 Angular、Vue 等框架構建,其節點可能爲組件動態渲染,因此 Selenium 在執行測試時可能獲取的 Dom 樹爲舊數據從而致使找不到節點,所以您能夠執行等待語句確保節點出現後再進行測試。不過可能不是 100% 成功,這也是這套測試系統的短板之一。

  • 若是您在進行模擬鼠標的測試,您的鼠標指針可能會干擾您的測試,所以建議運行測試後將您的指針移動至屏幕外部,以免干擾到瀏覽器測試。

  • 測試極可能由於頁面加載時間問題致使測試失敗,不過這也是 E2E 測試的特徵所在,您能夠修改您的測試邏輯,或致力縮短加載時間。

大功告成!

如今您已經擁有您本身的測試工具而且成功編寫了兩個測試用例!此處您應該爲本身鼓掌!
您如今已經能夠將 E2E 測試歸入您的開發流程之中,在下相信這將對您的開發有不小的幫助。若是您有興趣,您也能夠考慮 單元測試 的可能性。

若是您沒能成功構建您的項目,您能夠從這裏獲取代碼。

同時像以前提到的,若是您在使用 Vue 構建您的項目,您可使用 Vue-cli 來生成已經包含 Selenium 與 Nightwatch 的 Vue 種子項目,您能夠在 test/e2e 中編寫您的測試用例。

但願三篇簡單的短文能給您帶來幫助!⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄

相關文章
相關標籤/搜索