歡迎光臨
每天分享高質量文章

如何Docker化端到端驗收測試?

本文標的是充當使用Selenium Docker鏡像以及CodeceptJS和Express服務器的“操作方法”指南。
其中,我們將涵蓋:
  • 什麼是E2E驗收測試?

  • 為什麼要使用Docker?

  • 松耦合的測試工具

  • 測試工具層

  • 創建測試專案

E2E驗收測試

驗收測試是典型軟體開發過程中的一個階段。它涵蓋了測試用例,以確定產品是否符合總體需求規格,以及準備作為交付件是否“可接受”。它通常是在將產品投入生產之前的最後一道測試工序。這包括基於用戶的驗收測試,基於業務的驗收測試,甚至是alpha / beta測試。
端到端(E2E)測試是驗收測試的一種實現。這是驗收測試的一種方法,但這些術語不是同義詞。它允許從頭到尾測試應用程式的流程,看它是否按設計執行。以Web應用程式為例,它將涉及確定用戶場景並測試用戶按順序執行的每個步驟。如果場景未成功完成,則測試失敗。
市面上存在各種工具來自動化該過程,模擬用戶與應用程式的交互。
為何選擇Docker?

創建和運行E2E測試通常被認為是一個古怪和複雜的過程。它需要大量的設置,在不同的機器或CI(持續集成)環境中運行時仍然很容易失敗。為本地測試和CI測試安裝和維護不同的瀏覽器和WebDrivers需要時間。即使完成,它仍然會因為簡單的問題而失敗,例如開發人員的本地計算機或CI中的屏幕解析度是否不同。
Docker的標準優勢也適用:無需處理操作系統兼容性或安裝依賴項。要運行Selenium Server,你需要安裝Java(或者至少要顯式啟動/停止)。要運行Express,你需要Node.js,而對於Chrome,你需要Chrome本身以及ChromeDriver。
使用Docker可以消除這些依賴性。你只需使用已包含這些依賴的不同容器,無論它們在哪台機器上運行,它們的功能都完全相同。當你認為將Docker構建到CI中很容易時,Docker化你的測試過程將成為一個明顯的選擇。
松耦合的測試工具

在編寫E2E測試時有幾個框架可用,對於新手來說,很難知道選擇哪個去投入時間。如果你選錯了,那你就浪費了很多時間。
我們可以考慮使用CodeceptJS。 CodeceptJS是一個測試框架,採用場景驅動的行為驅動開發(BDD)方法,使用API語言,非工程師易於理解和使用。然而,或許更重要的是,它是後端不可知的。它是在幾個流行的測試庫(例如WebDriverIO或Puppeteer)之上編寫的,它的單個高級API可以與你選擇的任何一個進行通信。它的創造者相信:
你的測試不應該系結到你的執行引擎。無論你選擇Selenium還是Puppeteer,你的測試應該看起來幾乎相同。如果你(稍後)感覺到一個引擎的限制,你可以輕鬆地將測試切換到其他引擎。
測試工具層

模擬用戶與瀏覽器交互的每一層都有一些不同的產品
讓我們採用自下而上的方法來研究每一層如何構建在下一層之上。
入門時使用Selenium是值得的,Selenium是一個長期運行的專案,其中包含一組活躍使用的工具,現在由Selenium WebDriver,Grid,Server和IDE組成。在創建這些工具時,他們設定了許多行業標準,通常以他們來自的Selenium產品命名。這可以在’Selenium WebDriver’和在其開發中建立的’WebDriver線協議’中看到。適用的那些將在下麵更詳細地顯示。
瀏覽器
任何網絡瀏覽器:Chrome,Firefox,Internet Explorer,Safari,Opera等。通常在文件中稱為“用戶代理”。
W3C的WebDriver線路協議
WebDriver線路協議是一種與Web瀏覽器交互的平臺和語言中立方式。它定義了一個在請求/響應對中使用JSON over HTTP的通用RESTful Web服務。它允許從外部源操作DOM元素,同時還允許導航到網頁,用戶輸入,JavaScript執行等。
最初由Selenium為Selenium WebDriver編寫,該協議現已進入編輯草案階段,成為官方的W3C標準。
其他協議已經退出,這裡不會詳細介紹。所有解釋都將採用實現WebDriver線路協議的後端。
另一個值得註意的協議是Puppeteer使用的Chrome DevTools協議。 Puppeteer不使用Selenium Server,它捆綁了最新版本的Chromium,供本地使用。如果你想在Docker中運行Puppeteer,你可以使用CodeceptJS鏡像(Puppeteer和Nightmare附帶)或者按照官方指南創建可以支持它的自定義鏡像。
瀏覽器WebDrivers
這些是WebDriver線路協議的瀏覽器特定實現,例如ChromeDriver for Chrome或GeckoDriver for Firefox。每個都充當一個獨立的服務器,用於接收來自使用WebDriver API的客戶端的請求(通常是測試所在的位置)。為了與標的瀏覽器進行通信,必須安裝正確的WebDriver實現。
Selenium Server
如果測試用例是在定義它們的同一臺機器上運行,那麼使用的客戶端WebDriver API實現(如下所述)可以直接與瀏覽器WebDriver通信,並且不需要Selenium Server。
然而,如果要在不同的計算機上運行測試,無論是在CI中,在跨多個計算機或虛擬機(VM)的Selenium Grid設置中,在遠程測試平臺(如BrowserStack或SauceLabs)上,還是在Docker中,都要運行Selenium服務器。它充當代理,將來自客戶端WebDriver API的請求轉發到正確的瀏覽器WebDriver,並從瀏覽器傳迴響應。
正如我們稍後將看到的,’machine’也可以換成’container’
客戶端WebDriver實現
各種工具實現了客戶端WebDriver線路協議。這裡的協議可以看作是通過上述層向瀏覽器發送請求的API。許多使用該協議的工具都是完整的框架,例如WebDriverIO,它們包含自己的測試運行程式。
其他實現包括:原始的Selenium WebDriver,Protractor,Appium等。
每個庫的標的是實現相同的結果,但焦點和API實現略有不同。比如Protractor的browser.get(url)和WebDriverIO的browser.url(url)。
一個API統治所有
如本節開頭所述,這是CodeceptJS發揮作用的地方。它將其他客戶端WebDriver協議(或其它協議)實現為“幫助程式”,並允許你在使用一種API語言時指定你喜歡的幫助程式。 CodeceptJS並不關心所選幫助程式使用的協議。
WebDriverIO,Puppeteer,Protractor,Nightmare和Appium都是現有的幫助程式。
在CodeceptJS中,無論選擇哪個幫助程式,上一個命令都是I.amOnPage(url)。這意味著如果你想將後端切換到支持的其他幫助程式之一,則不必重新編寫測試。如果你願意,可以通過自定義類改寫或添加到預設API方法。

創建測試專案

有這麼多層,這聽起來開始複雜了,但在CodeceptJS的初始化腳本和Docker鏡像之間,我們可以快速找到一個有效的例子。
我們將產生什麼
現在將使用兩個容器,但這可以擴展
我們將在CodeceptJS中編寫一個簡單的測試,指定一個WebDriverIO後端幫助程式,它將與Docker容器中的遠程單機firefox瀏覽器進行通信。我們將使用Express“hello world”應用程式,但這可以被你希望的任何應用程式取代。
只需要兩個命令就能很快運行Dockerized應用程式和所有測試套件
一旦我們完成了所有設置,我們將只需運行兩個命令來運行測試:
  • docker-compose up –build

  • docker exec -it app npm run test:e2e

通過在兩個併排的終端視窗中運行,我們可以看到容器正在運行並且測試正在實時執行。
先決條件
Docker,適用於你正在開發的任何一臺機器。
你也可以安裝Node.js和npm進行本地開發和除錯,但這些也完全可以在Docker中運行。
檔案結構
我們將在下麵生成檔案結構。你可以在GitHub上看到一個工作示例[1]。
|-- .gitignore 
|-- output/
|-- Dockerfile
|-- app.js
|-- docker-compose.yml
|-- package.json
|-- package-lock.json
|-- e2eTests/
    |-- common_test.js
    |-- docker.conf.js

依賴
首先,我們將使用Express作為依賴項創建package.json,將CodeceptJS和WebDriverIO創建為dev依賴項。
{
  "name""example-standalone-firefox",
  "version""1.0.0",
  "description""Example of Dockerizing E2E testing",
  "scripts": {
    "start""node app.js",
    "test:e2e""codeceptjs run --steps --verbose --config=./e2eTests/docker.conf.js"
  },
  "dependencies": {
    "express""^4.16.3"
  },
  "devDependencies": {
    "codeceptjs""^1.2.0",
    "webdriverio""^4.12.0"
  }
}

我們還包括兩個腳本,一個用於運行我們將添加的Express應用程式(npm run start),另一個用於運行我們的CodeceptJS測試(npm run test:e2e)。
codeceptjs run --steps --verbose --config=./e2eTests/docker.conf.js

–steps非常適合在測試運行時在終端中顯示輸出,而–verbose則進一步擴展了詳細程度。 –verbose可能不需要作為標準,但有助於瞭解示例的工作原理。 –config向我們顯示後端配置檔案的路徑,在這種情況下儲存在單獨的e2eTests目錄中。
我們的應用
接下來我們需要一個應用來測試。 為此,我們將從app.js開始運行Express”hello world[2]”應用程式。
const express = require('express');

const app = express();

app.get('/'(req, res) => res.send('Hello World!'));

const server = app.listen(3000() => {
    const port = server.address().port
    console.log(`Example app listening on port ${port}`)
 })

你可以使用npm run start查看此內容,然後在瀏覽器中轉到localhost:3000。
測試配置
CodeceptJS需要兩個檔案,一個配置檔案和一個測試檔案。 測試檔案非常簡單:它測試應用程式是否可以訪問,儲存屏幕截圖,並檢查頁面上是否可以看到文本“Hello”。
Feature('Basic test');

Scenario('navigate to homepage', I => {
  I.amOnPage('http://app:3000');
  I.saveScreenshot('frontpageScreenshot.png');
  I.see('Hello');
});

我們將使用多個Docker容器的第一個跡象是,我們使用app:3000而不是localhost:3000來顯示。 localhost只能在單個容器中理解。 如果正在從另一個容器運行命令(在這種情況下是我們的第二個Selenium容器中的Firefox),那麼它需要更明確的取用。 我們可以直接使用第一個容器的IP地址,但使用容器的名稱更容易閱讀。
在這種情況下,app將是運行應用程式的容器的名稱,因此我們可以使用app:3000。 如果你還沒有遵循這一點,請不要擔心,看看我們的docker-compose.yml的結構將有所幫助。
我們還需要一個主配置檔案。 這可以用JSON或JS編寫,但在這裡我們使用JS。 我們來看看這個:
exports.config = {
  tests: './*_test.js',    // how to know which files are test files
  output: './output',      // where to save screenshots
  helpers: {
   WebDriverIO: {               // which backend helper to use
     url: 'http://app:3000',    // a base URL to start on
     host: 'firefox-container'// identifying where selenium runs
     browser: 'firefox',        // a series of config options
     smartWait: 5000,              
     waitForTimeout: 10000,
     desiredCapabilities: {        // for a demo app we do not want 
         acceptInsecureCerts: true,   to worry about SSL certs
     }
   },
  },
  name: 'codeceptjs-docker',
};
設置Docker
回到上面“我們將要生成什麼”部分的圖表,我們可以看到我們將使用兩個Docker容器。他們必須彼此瞭解並能夠溝通。一個將包含我們的應用程式和測試,一個包含Selenium Server,GeckoDriver和Firefox,因此我們不需要在本地計算機上安裝Firefox。
Docker Compose是一個“定義和運行多容器Docker應用程式的工具。”它使用命令docker-compose up啟動Docker容器,並使用docker-compose down停止它們。如果正在使用用戶定義的Dockerfile,則使用–build構建它,第一次運行docker-compose up,或者Dockerfile進行了更改。 docker-compose.yml都是定義up命令將執行的操作的檔案。
我們的下一步是創建這個docker-compose.yml。它嚴重依賴於縮進。
version: "2"        // which version of compose syntax you are using
services:
  app:
    container_name: app  // explicit so we can use this for app:3000
    build: .             // a self defined Dockerfile, see below
    ports:               // exposes port 3000 (where express runs)
      - "3000:3000"         to other containers, and to our local       
    depends_on:             browser
      - firefox-container
    volumes:             // maps so changes to these can be seen
      - ./e2eTests:/e2eTests
      - ./package.json:/package.json
      - ./package-lock.json:/package-lock.json
      - ./.gitignore:/.gitignore
      - ./app.js:/app.js

  firefox-container:      // we'll look at this below
    container_name: firefox-container
    image: selenium/standalone-firefox:3.12.0-americium
    volumes:
      - /dev/shm:/dev/shm
    ports:
      - "4444:4444"

對於我們的Selenium Server,驅動程式和瀏覽器,我們使用公共Docker Hub提供的預定義鏡像selenium/standalone-firefox。我們指定我們想要的版本,3.12.0-americ。如果我們沒有指定它,預設情況下將使用最新的鏡像(這不是一件壞事)。我們建議將其配置為共享主機的記憶體以防止瀏覽器崩潰,並公開端口4444(預設的Selenium端口)。我們還將此映射到本地計算機上的端口4444,允許我們在瀏覽器中訪問localhost:4444/wd/hub/static/resource/hub.html。
對於我們的app容器,我們不只是使用由其他人構建的鏡像,還編寫Dockerfile來指定我們的應用程式的構建方式。與selenium-firefox容器一樣,我們公開了一個端口,在這種情況下為3000,因為預設情況下Express是運行的。通過使用3000:3000進行映射,我們可以訪問localhost:3000,同時在Docker中運行應用程式以在我們的本地瀏覽器中查看它。
我們的Dockerfile使用公共的 node:carbon 鏡像作為基礎,設置工作目錄,將一些檔案從本地機器複製到容器,運行npm install以便容器具有所有需要的依賴項,然後運行我們指定的npm start命令。
FROM node:carbon 
WORKDIR ./ 
COPY ./package.json ./package-lock.json ./app.js ./ 
RUN npm install 
CMD [ "npm""start" ]

這意味著當docker-compose up –build運行時,它將遵循這些步驟,從而使我們的應用程式準備好併在端口3000上運行。
註意:只有在第一次運行docker-compose up時,或者對Dockerfile或其中執行的步驟進行了更改時,才需要–build標誌。例如,如果我們在package.json中添加了另一個依賴項,那麼如果我們沒有重建我們的鏡像,Docker就不會知道它,因為npm install在Dockerfile中運行。
運行測試
我們現在有一個簡單的應用程式,為它編寫的測試,以及將運行我們的應用程式,Selenium Server和Firefox的Docker Compose配置。
我們可以使用docker-compose up –build啟動所有這些。
要在正在運行的Docker容器中運行命令,可以從另一個終端視窗使用docker exec。格式為:
docker exex <flags> <container_name> <command>

我們將使用的命令是:
docker exec -ti app npm run test:e2e

我們現在可以看到我們的測試正在運行,併在執行時看到每個步驟!從這裡我們可以擴展我們的測試,添加額外的測試(以_test.js結束的檔案名),並使用相同的兩個命令來運行它們。無需更多設置。
你現在擁有一個易於擴展的E2E測試設置,無論運行哪台計算機,都可以依賴該設置以相同的方式運行。它是用API命令編寫的,開發人員和非開發人員都可以輕鬆理解。現在剩下的就是決定你的應用應該具備哪種行為,然後進行測試!

最後的話

SeleniumHQ還生成用於Chrome測試的Docker鏡像,以及使用Selenium Grid一次運行多個Chrome和Firefox實體的鏡像。
CodeceptJS還有在Docker中運行CodeceptJS的說明[3],因此不需要在應用程式中將其指定為依賴項。
關於Docker如何工作的更技術性但仍然是初級的描述可以在我寫的標題為亞馬遜彈性容器服務的初學者指南[4]的帖子的第一部分中看到。
感謝你的閱讀。
相關鏈接:
  1. https://github.com/dominicfraser/CodeceptJSDockerExamples/tree/master/seleniumStandaloneFirefox

  2. https://expressjs.com/en/starter/hello-world.html

  3. https://codecept.io/docker/

  4. https://medium.freecodecamp.org/amazon-ecs-terms-and-architecture-807d8c4960fd

原文鏈接:https://medium.freecodecamp.org/how-to-dockerize-your-end-to-end-acceptance-tests-dbb593acb8e0

Kubernetes實戰培訓

Kubernetes應用實戰培訓將於2018年10月12日在深圳開課,3天時間帶你系統學習Kubernetes本次培訓包括:容器基礎、Docker基礎、Docker進階、Kubernetes架構及部署、Kubernetes常用物件、Kubernetes網絡、儲存、服務發現、Kubernetes的調度和服務質量保證、監控和日誌、Helm、專案實踐等,點擊下方圖片查看詳情。

赞(0)

分享創造快樂