最受歡迎的 5 款 Node.js 端到端測(cè)試框架

共 7717 字,讀完需 10 分鐘翩瓜,速讀需 5 分鐘,適合中高級(jí)前端工程師嗜桌,本文對(duì)主流的 E2E 測(cè)試框架做了簡(jiǎn)單對(duì)比奥溺,期望對(duì)大家的技術(shù)選型有幫助。

測(cè)試骨宠,尤其是自動(dòng)化測(cè)試在現(xiàn)代 WEB 工程中有著非常重要的角色,與交付過程集成良好的自動(dòng)化測(cè)試流程可以在新版發(fā)布時(shí)幫你快速回歸產(chǎn)品功能相满,也可以充當(dāng)產(chǎn)品文檔层亿。測(cè)試因粒度不同又可以分為單元測(cè)試、接口測(cè)試立美、功能測(cè)試匿又。在 WEB 領(lǐng)域,功能測(cè)試亦稱為端到端測(cè)試End to End Test建蹄,簡(jiǎn)稱 E2E 測(cè)試)碌更,筆者在本文中會(huì)結(jié)合自身實(shí)踐和 GitHub 趨勢(shì)對(duì)比最受歡迎的 Node.js E2E 測(cè)試解決方案,首先我們按 GitHub 的 star 總數(shù)量排序洞慎,取前 5 名列舉如下(注意:你閱讀本文時(shí) star 的數(shù)量可能已經(jīng)不是最新的)痛单。

  • CasperJS — 6460 個(gè) star,官網(wǎng)劲腿,代碼旭绒,最近更新于 7 天前;
  • Protractor — 6408 個(gè) star焦人,官網(wǎng)挥吵,代碼,最近更新于 10 天前花椭;
  • Nightwatch.js — 6121 個(gè) star忽匈,官網(wǎng)代碼矿辽,最近更新于 6 天前丹允;
  • TestCafe — 2268 個(gè) star郭厌,官網(wǎng)代碼嫌松,最近更新于 1 天前沪曙;
  • CodeceptJS — 1087 個(gè) star,官網(wǎng)萎羔,代碼液走,最近更新于 7 天前;

然后分別從環(huán)境搭建贾陷、測(cè)試編寫缘眶、測(cè)試報(bào)告等方面來直觀展示這 5 個(gè) E2E 測(cè)試框架,期望能夠?qū)ψ鰷y(cè)試框架選型的同學(xué)有幫助髓废。為了更客觀的體現(xiàn)各測(cè)試框架的特點(diǎn)巷懈,筆者設(shè)計(jì)了一些包含 E2E 測(cè)試中常用操作的測(cè)試用例,分別使用不同的框架來編寫慌洪。E2E 測(cè)試的常用操作如下:

  • 打開網(wǎng)頁顶燕,跳轉(zhuǎn)網(wǎng)頁:打開 Github 的首頁;
  • 填寫輸入框冈爹,提交表單:鍵入搜索詞涌攻,提交搜索表單;
  • 元素單擊等操作:?jiǎn)螕羲阉鹘Y(jié)果的第一項(xiàng)频伤;
  • 元素?cái)?shù)量恳谎、屬性檢視:確認(rèn)搜索結(jié)果展示了 10 條;
  • 頁面運(yùn)行環(huán)境檢視:確認(rèn)頁面的地址是正確的憋肖;

CasperJS

CasperJS 是 star 數(shù)最高的測(cè)試框架因痛,也是筆者最早開始采用的 E2E 測(cè)試框架,使用 Python 編寫岸更,雖不算是嚴(yán)格意義上的原生 Node.js 解決方案鸵膏,但因?yàn)槟軌蚴褂?npm 安裝,且能夠很好的與 Node.js 工具鏈組合使用坐慰,筆者還是把它列在了這里较性。其特別之處在于只能與無界面瀏覽器(Headless Browser)組合使用,比如 PhantomJSSlimerJS结胀,這也讓 CasperJS 的優(yōu)勢(shì)顯而易見:測(cè)試運(yùn)行速度比真實(shí)瀏覽器快不少赞咙,且你不需要在持續(xù)集成系統(tǒng)中安裝各種瀏覽器或者某個(gè)瀏覽器的不同版本;潛在的坑在于糟港,無界面瀏覽器的表現(xiàn)有時(shí)和真實(shí)瀏覽器不完全相同攀操,會(huì)帶來某些難以排查解決的瀏覽器兼容問題。

安裝步驟

  • 安裝 Python 2.6 或更高版本
  • 安裝 PhantomJS:npm install -g phantomjs
  • 安裝 CasperJS:npm install -g casperjs

編寫測(cè)試

如果使用 ES6 之前的風(fēng)格來編寫 CasperJS 測(cè)試秸抚,代碼看起來會(huì)顯得非常臃腫速和,而實(shí)際上 CasperJS 也不支持任何 ES6/ES7 的新語法歹垫,除非你在運(yùn)行測(cè)試之前自己對(duì)代碼進(jìn)行預(yù)編譯,實(shí)際代碼如下:

casper.test.begin('Github Search', function suite(test) {
    casper.start('https://github.com', function () {    // 打開首頁
        test.assertVisible('.js-site-search-form', 'should search input visible');
        this.fill('.js-site-search-form', { q: 'casperjs' }, true); // 鍵入搜索詞颠放、并提交
    });

    casper.then(function () {
        test.assertEval(function() {    // 確認(rèn)搜索結(jié)果是 10
            return __utils__.findAll('.repo-list-item').length >= 10;
        }, 'should show 10 results');
    });

    casper.then(function () {
        this.click('.repo-list-item h3 a'); // 點(diǎn)擊第1條結(jié)果
    });

    var location = null;

    casper.then(function () {   // 這里是取環(huán)境變量
        test.assertVisible('.repository-content', 'should repo detail visible');
        location = this.evaluate(function () {
            return window.location;
        });
    });

    casper.then(function () {   // 確認(rèn)目前跳轉(zhuǎn)到了 casperjs 官方倉庫
        test.assertEquals(location.pathname, '/casperjs/casperjs', 'should casperjs repo found');
    });

    casper.run(function () {
        test.done();
    });
});

因?yàn)?CasperJS 對(duì) CoffeeScript 有天然的支持排惨,熟悉 CoffeeScript 的同學(xué)可以嘗試使用 CoffeeScript 編寫測(cè)試,或者使用這個(gè)工具轉(zhuǎn)換為 CoffeScript碰凶。

運(yùn)行測(cè)試

casperjs test casperjs/test.js

查看報(bào)告

測(cè)試通過

測(cè)試失敗

Protractor

ProtractorAngular 官方正在使用的 E2E 測(cè)試框架暮芭,可以說是專門為 Angular 定制,內(nèi)置了各種可以選擇欲低、操作 Angular 元素的便捷方法辕宏,如果你的應(yīng)用基于 Angular 開發(fā),使用它可以減少很多重復(fù)代碼(顯然類似的便利在其他框架中也有支持)砾莱。對(duì)于 Angular 的重度使用者瑞筐,Protractor 會(huì)是非常明智的選擇,不同于 CasperJS 的是 Protractor 在真實(shí)瀏覽器中運(yùn)行測(cè)試代碼腊瑟。此外聚假,Protractor 內(nèi)置的頁面加載等待的功能,在 CasperJS 中需要自己設(shè)置合理的超時(shí)闰非。相比于本文列出的其他框架魔策,Protractor 的明顯優(yōu)勢(shì)是測(cè)試用例的組織方式可以自由使用 Jasmine 或者 Mocha

安裝步驟

  • 安裝 JDK
  • 安裝 Protractor:npm install –g protractor
  • 初始化 WebDriver Manager:webdriver-manager update
  • 創(chuàng)建配置文件

編寫測(cè)試

Protractor 默認(rèn)開啟了等待 Angular 加載并初始化完成的功能河胎,如果你測(cè)試的不是 Angular 應(yīng)用,則需要關(guān)閉這個(gè)功能虎敦,測(cè)試代碼示例如下:

describe('angularjs homepage todo list', function () {
    browser.ignoreSynchronization = true;   // 不啟用智能等待游岳,因?yàn)?github 不是用 angluar 編寫的
    browser.get('https://github.com');

    it('should search input visible', function () {
        var searchInput = element(by.className('js-site-search-focus'));
        var searchForm = element(by.className('js-site-search-form'));
        expect(searchInput.isDisplayed()).toEqual(true);
        searchInput.sendKeys('protractor');
        searchForm.submit();
    });

    it('should show 10 results', function () {
        var searchList = element.all(by.className('repo-list-item'));
        expect(searchList.count()).toEqual(10);
        element(by.css('.repo-list-item h3 a')).click();
    });

    it('should repo detail visible', function () {
        var repoContent = element.all(by.className('repository-content'));
        expect(repoContent.isDisplayed()).toEqual([true]);
    });

    it('should protractor repo found', function (done) {
        browser.executeScript(function () {
            return window.location;
        }).then(function (location) {
            expect(location.pathname).toEqual('/angular/protractor');
            done();
        });
    });
});

運(yùn)行測(cè)試

  • 運(yùn)行 WebDriver Manager: webdriver-manager start
  • 運(yùn)行測(cè)試:protractor protractor.config.js

查看報(bào)告

測(cè)試通過

測(cè)試失敗

Nightwatch

同樣流行的 Nightwatch,可以認(rèn)為是 Protractor 的主要競(jìng)爭(zhēng)對(duì)手其徙,使用 Nigthwatch 編寫的代碼非常簡(jiǎn)潔胚迫,但是你需要手動(dòng)在測(cè)試代碼中添加合適的等待來保障測(cè)試的穩(wěn)定,而 Protractor 和 TestCafe 則提供了內(nèi)置的支持唾那;Nightwatch 的主要劣勢(shì)在于繁瑣的安裝步驟访锻,可能部分同學(xué)看到這個(gè)安裝文檔或者下面的安裝步驟就知難而退了。

安裝步驟

編寫測(cè)試

module.exports = {
    'Github Search': function (browser) {
        browser // 打開首頁、填寫搜索詞沙庐、提交搜索表單
            .url('https://github.com')
            .assert.visible('.js-site-search-focus', 'should search input visible')
            .setValue('.js-site-search-focus', 'nightwatch')
            .submitForm('.js-site-search-form')
            .pause(1000);

        browser.execute(function () {   // 確認(rèn)展示 10 條搜索結(jié)果
            return document.querySelectorAll('.repo-list-item').length;
        }, function (args) {
            browser.assert.equal(args.value, 10, 'should show 10 results');
        });

        browser.click('.repo-list-item h3 a').pause(1000);

        browser.assert.visible('.repository-content', 'should repo detail visible');

        browser.execute(function () {
            return window.location;
        }, function (args) {    // 確認(rèn)打開了 nightwatch 官網(wǎng)
            browser.assert.equal(args.value.pathname, '/nightwatchjs/nightwatch', 'should nightwatch repo found');
        });

        browser.end();
    }
};

運(yùn)行測(cè)試

  • 運(yùn)行 Selenium:java -jar selenium-server-standalone-3.0.0.jar
  • nightwatch test.js

查看報(bào)告

測(cè)試通過

測(cè)試失敗

TestCafe

TestCafe 是非常年輕但很受開發(fā)者歡迎的測(cè)試框架鲤妥,因?yàn)椴恍枰蕾?WebDriver 之類的東西佳吞,TestCafe 環(huán)境只需一鍵即可完成,這也意味著棉安,你可以在任何安裝了瀏覽器應(yīng)用的物理設(shè)備上運(yùn)行測(cè)試底扳。TestCafe 對(duì) ES6/ES7 語法的天然支持讓它更具前瞻性,命令行工具產(chǎn)生的測(cè)試報(bào)告簡(jiǎn)潔但不失完整贡耽。由于開源的時(shí)間較短衷模,相比于其他測(cè)試框架 TestCafe 的社區(qū)和生態(tài)還不夠成熟。盡管如此菇爪,不斷出現(xiàn)的各種 TestCafe 功能擴(kuò)展也證明了它的社區(qū)和生態(tài)在不斷壯大算芯。對(duì)于站在 WEB 技術(shù)風(fēng)口浪尖的同學(xué),TestCafe 無疑是非常值得留意的 E2E 測(cè)試解決方案凳宙,開箱即用的特性極大的降低了使用者的成本熙揍。

安裝步驟

npm install testcafe -g

編寫測(cè)試

TestCafe 的測(cè)試組織方式詳見這里選擇符支持也非常強(qiáng)大氏涩,支持類似于 jQuery 的靈活異步的選擇符届囚,斷言風(fēng)格非常類似 Chai,下面是測(cè)試代碼:

import { Selector } from 'testcafe';

fixture `Github Search`
    .page `https://github.com`;

test('should github search work as expected', async t => {
    const searchInput = Selector('.js-site-search-focus');
    const searchList = Selector('.repo-list-item');
    const resultItem = Selector('.repo-list-item h3 a');
    const repoContent = Selector('.repository-content');

    await t.setTestSpeed(0.8);
    await t.expect(searchInput.exists).eql(true, 'should search input visible');
    await t.typeText(searchInput, 'testcafe');
    await t.pressKey('enter');

    await t.expect(searchList.count).eql(10, 'should show 10 results');
    await t.click(resultItem);

    await t.expect(repoContent.exists).eql(true, 'should repo detail visible');

    const location = await t.eval(() => window.location);
    await t.expect(location.pathname).eql('/DevExpress/testcafe', 'should testcafe repo found');
});

運(yùn)行測(cè)試

testcafe chrome testcafe/test.js

查看報(bào)告

測(cè)試通過

測(cè)試失敗

CodeceptJs

CodeceptJs 可能并不算是嚴(yán)格意義的 E2E 測(cè)試框架是尖,它對(duì)各種測(cè)試運(yùn)行工具做了一層封裝意系,旨在提供更簡(jiǎn)潔的 API,你可以自由選擇下面這些測(cè)試運(yùn)行工具:

  • WebDriverIO
  • Protractor
  • Selenium WebDriver JS
  • NightmareJS

CodeceptJs 讓筆者比較欣賞的地方在于測(cè)試用例的組織饺汹,基于 FeatureScenario 兩個(gè)粒度來組織測(cè)試讓它看起來更有 E2E 測(cè)試的樣子蛔添,它支持最新的 ES6 語法季眷,同時(shí)也屏蔽各種復(fù)雜的回調(diào)細(xì)節(jié)推励,所有的測(cè)試用例都是以第一人稱來做,讓測(cè)試代碼閱讀起來更像是自然語言吴旋,而讓筆者擔(dān)憂的地方在于逸吵,過多的封裝可能導(dǎo)致出問題時(shí)排查比較困難凶硅。

安裝步驟

  • 安裝 CodeceptJs npm install -g codeceptjs
  • 用命令行工具初始化配置 codecept.jsoncodeceptjs init
  • 使用命令行工具生成測(cè)試:codeceptjs gt
  • 此外,你需要安裝你所選擇的底層測(cè)試工具扫皱,比如 WebDriver足绅、Protractor

編寫測(cè)試

Feature('Github Search');

Scenario('search codecept repo', (I) => {
    I.amOnPage('https://github.com');
    I.seeElement('.js-site-search-focus');
    I.fillField('.js-site-search-focus', 'codeceptjs');
    I.pressKey('Enter');

    I.seeElement('.repo-list-item');
    I.click('.repo-list-item h3 a');
    I.seeElement('.repository-content');
    I.seeInCurrentUrl('/Codeception/CodeceptJS');
});

運(yùn)行測(cè)試

codeceptjs run

查看報(bào)告

測(cè)試通過

測(cè)試失敗

總結(jié)對(duì)比

本文中的所有代碼可以在 GitHub 倉庫上看到。任何開發(fā)工具的演化都是朝著更快捷韩脑、高效的目標(biāo)氢妈。本文介紹的幾個(gè) E2E 測(cè)試框架可以說各有所長(zhǎng),在做框架選型的時(shí)候該考慮哪些因子呢扰才?這些因子的優(yōu)先級(jí)如何允懂?下面是筆者的考慮:

  • 上手簡(jiǎn)單:P0,環(huán)境搭建步驟衩匣?出錯(cuò)的概率蕾总?是否需要繁瑣的配置粥航?TestCafe 非常簡(jiǎn)單;
  • 文檔支持:P0生百,是否包含入門文檔递雀?API 參考?開發(fā)者文檔蚀浆?本文中的五款都還不錯(cuò)缀程;
  • 過程透明:P0,測(cè)試運(yùn)行過程是否是透明的市俊,能否觀察到頁面行為杨凑?CasperJS 就像個(gè)黑盒;
  • 運(yùn)行速度:P0摆昧,測(cè)試運(yùn)行速度能決定你 CI 流程的好壞撩满;
  • 測(cè)試報(bào)告:P0,是否支持多種報(bào)告绅你?是否方便與 CI 流程集成伺帘?比如要支持 XML、JUnit 等格式輸出忌锯;
  • 調(diào)試功能:P0伪嫁,出錯(cuò)時(shí)提供的信息是否清晰?是否支持截圖偶垮?TestCafe 做的很好张咳;
  • 測(cè)試組織:P1,是否能與現(xiàn)有的技術(shù)棧很好的組合起來似舵?不能結(jié)合獨(dú)創(chuàng)的方式是否直觀晶伦?如果是大型項(xiàng)目可以提高優(yōu)先級(jí),Protractor 和 CodeCeptJs 占優(yōu)啄枕;
  • 代碼風(fēng)格:P1,簡(jiǎn)潔的代碼意味的更高的可讀性族沃、更低的維護(hù)成本频祝;TestCafe、CodeCeptJs 不錯(cuò)脆淹;
  • 社區(qū)支持:P2常空,圍繞這個(gè)工具是否有成熟的社區(qū)?可以用來提問盖溺、貢獻(xiàn)代碼漓糙;
  • 可擴(kuò)展性:P3,是否支持 API 擴(kuò)展烘嘱?擴(kuò)展成本如何昆禽?

如果你的項(xiàng)目中需要添加 E2E 測(cè)試蝗蛙,做決定的時(shí)候沒有標(biāo)準(zhǔn)答案,因?yàn)檫€需要結(jié)合項(xiàng)目自身的特點(diǎn)醉鳖,比如規(guī)模大小捡硅、對(duì)上面各因子的要求。

備注:本文的初始版本來源于 Medium 上的文章盗棵,但是筆者在原文基礎(chǔ)上重新設(shè)計(jì)了測(cè)試用例壮韭,每個(gè)測(cè)試框架的介紹也參與了筆者自身的使用經(jīng)驗(yàn),框架選型上也融入了自己的思考纹因,有興趣的可以去看原文喷屋。

One More Thing

本文首發(fā)知乎專欄,商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)瞭恰,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處屯曹。如果對(duì)文中的內(nèi)容有任何疑問,歡迎留言討論寄疏。想知道我接下來會(huì)寫些什么是牢?歡迎訂閱知乎專欄:《前端周刊:讓你在前端領(lǐng)域跟上時(shí)代的腳步》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陕截,一起剝皮案震驚了整個(gè)濱河市驳棱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌农曲,老刑警劉巖社搅,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異乳规,居然都是意外死亡形葬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門暮的,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笙以,“玉大人,你說我怎么就攤上這事冻辩〔螅” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵恨闪,是天一觀的道長(zhǎng)倘感。 經(jīng)常有香客問我,道長(zhǎng)咙咽,這世上最難降的妖魔是什么老玛? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上蜡豹,老公的妹妹穿的比我還像新娘麸粮。我一直安慰自己,他們只是感情好余素,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布豹休。 她就那樣靜靜地躺著,像睡著了一般桨吊。 火紅的嫁衣襯著肌膚如雪威根。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天视乐,我揣著相機(jī)與錄音洛搀,去河邊找鬼。 笑死佑淀,一個(gè)胖子當(dāng)著我的面吹牛留美,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伸刃,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼谎砾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了捧颅?” 一聲冷哼從身側(cè)響起景图,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碉哑,沒想到半個(gè)月后挚币,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扣典,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年妆毕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贮尖。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笛粘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出湿硝,到底是詐尸還是另有隱情闰蛔,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布图柏,位于F島的核電站,受9級(jí)特大地震影響任连,放射性物質(zhì)發(fā)生泄漏蚤吹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裁着。 院中可真熱鬧繁涂,春花似錦、人聲如沸二驰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桶雀。三九已至矿酵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矗积,已是汗流浹背全肮。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棘捣,地道東北人辜腺。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乍恐,于是被迫代替她去往敵國和親评疗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容