WebDriverIO with CI,我們選擇 Jenkins 協助我們完成持續整合與自動化測試,應用服務的執行環境使用 Docker,讓測試用 Server 不用額外安裝前端測試需要的瀏覽器或工具,只要有 Docker engine 就可以滿足需求,有效隔離環境與單純化前置作業。
這裡也會透過 Jenkins 結合 Slack,讓建置過程寄發到相關群組,可更為有效的讓開發人員快速的獲得訊息並做出相對應的處理。
以下是專案測試執行步驟:
- 使用者異動到被測試專案與測試專案
- 觸發 Jenkins 執行測試專案 Task
- 執行成功或失敗將會產出 junit 報表
- 寄發 Slack 到群組通知
我們還是延續前幾篇 WebDriverIO 的 repository,進行設定檔的增加與調整,讓我們串起一整條鏈吧!
專案設定檔案 (wdio-demo)
我們必須重新設置 docker-compose,因為這次我們連專案執行環境都包起來給 docker,我們也需要 Dockerfile 來建置專案 image,把 repo 與依賴套件建立起來,真正施行一個在測試環境僅需要 docker 依賴套件的 Server。
Dockerfile
FROM node:8 COPY ./ /wdio-demo WORKDIR /wdio-demo RUN npm install
docker-compose.yml
version: '3' services: firefox: image: selenium/node-firefox:2.53.1 volumes: - /dev/shm:/dev/shm depends_on: - hub environment: - HUB_PORT_4444_TCP_ADDR=hub - HUB_PORT_4444_TCP_PORT=4444 networks: - front-tier chrome: image: selenium/node-chrome:2.53.1 volumes: - /dev/shm:/dev/shm depends_on: - hub environment: - HUB_PORT_4444_TCP_ADDR=hub - HUB_PORT_4444_TCP_PORT=4444 networks: - front-tier hub: container_name: wdio-demo_hub image: selenium/hub:2.53.1 ports: - "4444:4444" expose: - "4444" networks: - front-tier # test: # container_name: test # image: wdio-demo # depends_on: # - firefox # - chrome # volumes: # - ./test-reports:/wdio-demo/test-reports # working_dir: /wdio-demo # command: "npm test" # networks: # - front-tier networks: front-tier: driver: bridge
註解掉的那塊先不管它,因為我需要的是進行專案的測試成功與失敗能夠反饋到 Jenkins 的 Task,而不是 docker-compose 悄悄的做掉。所以測試專案的進行我拉出來額外進行 docker run 來進行 webdriverio 的專案測試。
你會看到我多了 docker networks 設置,因為要能透過容器的內部通信,所以我選擇 networks,其實你用 --link
也可以,主要讓 hub 設置可以不用綁內網 IP。
wdio.conf.js
exports.config = { // ... host: 'wdio-demo_hub', port: 4444, // ... reporters: ['dot', 'spec', 'junit'], reporterOptions: { junit: { outputDir: './test-reports' } }, // ... }
wdio.conf.dev.js
exports.config = { // ... // host: 'wdio-demo_hub', // port: 4444, // ... reporters: ['dot', 'spec'], // reporters: ['dot', 'spec', 'junit'], // reporterOptions: { // junit: { // outputDir: './test-reports' // } // }, // ... }
wdio.conf.dev.js 差別在於報表不匯出 junit,以及 host 與 port 註解掉以本機為主。
package.json
{ "name": "wdio-demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev-test": "wdio wdio.conf.dev.js", "dev-watch-test": "chimp --mocha --watch --path=test", "test": "wdio wdio.conf.js", "start-selenium-server-with-docker": "docker-compose down && docker-compose up -d", "build-with-docker": "docker build -t wdio-demo .", "run-test-with-docker": "docker rm -f wdio-demo_test || true && docker run -i --rm -v $(pwd)/test-reports:/wdio-demo/test-reports --network=wdiodemo_front-tier --name=wdio-demo_test wdio-demo npm test", "test-with-docker": "npm run start-selenium-server-with-docker && npm run build-with-docker && npm run run-test-with-docker" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "app-root-path": "^2.0.1", "chai": "^4.1.2", "chimp": "^0.51.0", "mocha": "^5.0.0", "wdio-junit-reporter": "^0.3.1", "wdio-mocha-framework": "^0.5.12", "wdio-spec-reporter": "^0.1.3", "wdio-testingbot-service": "^0.1.7", "webdriverio": "^4.10.1" } }
我們的 npm script 變更了,主要會運用到 test、dev-test、dev-watch-test 與 test-with-docker,執行內容與 Jenkinsfile 的一些 stage 是相同的。
(P.S. 若需使用到即時監聽測試 (chimp),需另外安裝 chimp 到 global (npm install chimp -g),在 test case 加上 @watch 標註,即可監聽該 test case)。
Jenkinsfile
node { def jobName = JOB_NAME.replace("-", "").replace("_", "").toLowerCase(); try { notifyBuild('STARTED') stage 'checkout' git 'https://github.com/eden90267/wdio-demo' stage 'start selenium-server' sh 'docker-compose up -d' stage 'build' sh 'docker build -t wdio-demo .' stage 'test' sh 'docker run -i --rm -v $(pwd)/test-reports:/wdio-demo/test-reports --network=' + jobName + '_front-tier wdio-demo npm test' } catch (e) { // If there was an exception thrown, the build failed currentBuild.result = "FAILED" throw e } finally { stage 'report' junit 'test-reports/*.xml' // Success or failure, always send notifications notifyBuild(currentBuild.result) sh 'docker-compose down' } } def notifyBuild(String buildStatus = 'STARTED') { // build status of null means successful buildStatus = buildStatus ?: 'SUCCESSFUL' // Default values def colorName = 'RED' def colorCode = '#FF0000' def subject = "${buildStatus}: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'" def summary = "${subject} (${env.BUILD_URL})" // Override default values based on build status if (buildStatus == 'STARTED') { color = 'YELLOW' colorCode = '#FFFF00' } else if (buildStatus == 'SUCCESSFUL') { color = 'GREEN' colorCode = '#00FF00' } else { color = 'RED' colorCode = '#FF0000' } // Send notifications slackSend baseUrl: 'https://104corp.slack.com/services/hooks/jenkins-ci/', channel: '#cteam-jenkins-ci', color: colorCode, message: summary, tokenCredentialId: 'jenkins-ci-integration-slack-token' }
Jenkinsfile 是給 Jenkine 2.0 pipeline 使用的,我們將專案部署環境設置放置到各專案使之版控化與透明化,更拉近了 DevOps 的施行精髓。
裡面有 try catch 設置,只要失敗即會寄送 Slack 失敗訊息並 throw 例外,成功的話則寄送 Slack 成功訊息,裡面也會有訊息的顏色配置,無論成功或失敗,都會產生 junit 報表。
安裝與設置 CI Server、Testing Server
- ubuntu 14.04
- openjdk 1.8
- jenkins 2.x
- docker engine 17.x
- docker-compose 1.18.0
其實應該 CI Server 與 Testing Server 要各自獨立,並開一個 docker private registry 作為儲存 docker image,之間透過 ssh 互相拋接資料,不過這裡僅當練習範例用,就將他們是同一台 Server 了。
安裝步驟我就不詳述了,網路上的範例非常之多 (抑或我之後開一個文章來 step by step 安裝 Jenkins 與基本配置),至於 Jenkins 我並沒有讓他 docker 化,因我將它歸類為 stageful 的服務,一般要 volume 設定的服務就可以選擇不 docker 化,所以我將 Jenkins 拉出來為一個 ubuntu service,實際 Testing、Staging or Production 環境 CI Server 也會獨立一台的。
設置 Task
- 主專案
- 測試專案
主專案僅須設置輪詢 SCM 為每 5 分鐘 (有 git trigger 更好),然後設置建置後動作為 測試專案 建置。這樣即可在主專案有 git push 新 master branch,即會觸發 測試專案 的建置。
測試專案不只設置輪詢 SCM 為每 5 分鐘外,也增加了半夜兩點會定期建置,增加測試施行次數來提升品質,早上開發人員即可看到每天測試結果如何。
至於 pipeline 設置我是直接吃專案的 Jenkinsfile:
安裝 Slack Notification Plugin
嗯,重點是你公司有 Slack workspace,裡面便有 Jenkins CI App 服務,我就直接進行 Add Configuration 的設置,裡面的步驟非常清楚,也可以參考 Jenkins 這篇:https://plugins.jenkins.io/slack。要是沒有,就做 email 的通知吧!
我們因為使用 Jenkins pipeline 關係,無法設置 Slack 全域設定 (會吃不到),需要在 Jenkinsfile 設置清楚相關 baseUrl、channel 與 token,token 我是用 Jenkins 的 secret file,比較安全些。
執行測試吧!
這是我的測試過程:
pipeline 的好處就是透明化了建置過程 (Stage),讓從前的僅有成功與失敗的結果現在演變成了各建置步驟的明朗化,有效提升部署人員的完善檢視,並能從各建置步驟查看相關資訊,從中再持續改善。 (像我這裡 build stage 的時間久了點,就可考慮將 Dockerfile 做妥善的 image min 化處理)
以下是 Slack 通知畫面:
以上步驟讓我們簡單串起來一個測試自動化鏈,透過 CI Server 協助我們觸發測試專案建置、產生測試報告與寄發 Slack 通知,這樣的測試鏈還有很多優化細節,譬如額外拉一條 testing server 與 docker private registry 做更為妥善的規劃,這些就交給各位讀者去優化了。