1. 程式人生 > >前端開源專案持續整合三劍客

前端開源專案持續整合三劍客

開發業務程式碼的時候,我們總能發現一些通用的功能。這時候,作為一個在網際網路時代富有分享精神的程式設計師,就會想要把專案開源出去,讓更多的小夥伴去使用,偶爾可能會有大神評論,能學到很多。 在 GitHub 上, README 是最先讓人看到的,一些應用廣泛的專案的 README ,除了非常詳細的文字介紹,還常常會帶有很多小徽章,比如 Vue 的這個 README 的開頭:

Vue

Vue

這些徽章 (badage) 展示了程式碼的測試覆蓋率構建狀態在各個瀏覽器中的執行情況,這會讓專案顯得更加專業和有說服力。本文以筆者集齊了一套徽章的親身經歷,總結了過程中的主要流程和一些踩到的坑,歡迎大家補充,讓我們的專案流行起來!

首先,安利一下我們開發的一個基於 React Material Design 的元件庫 Melon,歡迎大家使用,如果能加個星,提個 pr 就更歡迎了。

測試程式碼的重要性

靠人工來保證專案的維護總是不出差錯是不靠譜的,人總有健忘和糊塗的時候,尤其是當專案越來越複雜時,一個人甚至可能無法全部瞭解專案的全部邏輯,這時我們就要依靠測試來保證專案的可靠性,這裡的測試包括但不限於,單元功能測試,UI 測試,相容性測試等等。

關於單測框架已經有很多教程和文件,一個測試體系大體應該包含四部分

其中,jasmine 是一個比較完整的測試框架,還自帶了豐富的斷言函式,在編寫測試用例的時候不再需要單獨去引用斷言庫。以 Melon 專案為例,筆者使用的是 karma+jasmine+istanbul 的組合,由於這是基於 React 的庫,並且程式碼是 ES6 編寫的,因此需要加上 browserify babelify 這些外掛。

有了一整套測試體系,編寫完程式碼的測試用例,就可以開始應用下面的三個工具幫你生成徽章了

持續整合

持續整合是一種軟體開發實踐,即團隊開發成員經常整合它們的工作,通過每個成員每天至少整合一次,也就意味著每天可能會發生多次整合。每次整合都通過自動化的構建(包括編譯,釋出,自動化測試)來驗證,從而儘早地發現整合錯誤。

GitHub 上比較主流的持續整合工具有 Travis CI Circle CI,下面以 Travis CI 為例:

第一步 註冊

進入 Travis 的 首頁 有個 Sign Up 的大按鈕,點選進入就行了。第一次會進入一個github的登入頁面,可以選擇你想要開源的專案所在的組。有可能你不是這個組的Owner,並且這個組還沒有開通連線 Travis 的服務,需要聯絡 Owner 去開通。

第二步 建立 .travis.yml

在專案根目錄下建立 Travis 的配置檔案,如下(如果沒有這個檔案,Travis 會預設執行 npm install npm test):

1
2
3
4
5
6
7
8
9
10
language: node_js
node_js:
    - 4
install:
|
    npm install -g npm@latest
    npm --version
    npm install --registry http://registry.npmjs.org
script:
    - npm run test-ci

這是按照 YAML 的語法來寫的,通過這個配置檔案,我們需要告訴 Travis 伺服器,我們的程式碼是用什麼語言編寫的(language)、每次構建之前需要執行什麼命令來安裝依賴包(install)、怎麼執行測試程式(script)。對於 Node.js 我們還需要指定 Node 的版本,我們也可以設定多個 Node 版本來檢測一些 Node 端工具的相容性。當 node_js 配置設定了多個時,Travis 會同時建立多個 Job 來執行。 更多的配置可以參考 Travis 的官方文件

這裡有一個坑,如果安裝的時候不指定 npm 源,Babel 的有一些依賴包都會神奇得掛掉,導致構建直接終止,當你的專案出現這種問題了,不妨試試加一下 --registry http://registry.npmjs.org

如果覺得每次都安裝 npm 包太費時,Travis 有 cache 的功能,可以看文件配置

第三步 提交程式碼

每次程式碼 push 以後,Travis 會自動開始構建,並執行單測,構建成功以後就可以把徽章加到 README 裡了

1
[![Build](https://img.shields.io/travis/react-melon/melon-core.svg)](https://travis-ci.org/react-melon/melon-core)

程式碼覆蓋率整合

寫完整單元測試程式碼是維護一個快速迭代專案不出差錯的有效方法,程式碼覆蓋率報告可以為編寫測試程式提供參考。通過一些工具,還可以及時的把你的程式碼的測試情況及時的反饋給使用者,讓使用者感知你的測試是否完備。

第二位劍客登場: 它可以幫你生成一個展示程式碼覆蓋率的徽章: Coverage Status

第一步 註冊

開啟 Coveralls 官網,點選紅框中的按鈕再開啟的頁面中選擇 GITHUB SIGN UP,後面類似 Travis CI。

圖片圖片

註冊完成以後,就可以在 Dashboard 裡面看到自己所有在 GitHub 上的程式碼庫了。

第二步 建立 .coveralls.yml

進入 Coveralls 中相關程式碼庫的的詳情頁,如果你有許可權,可以看到一個 TOKEN 的格子,把這個 token 複製一下。在專案的根目錄新建一個檔案 .coveralls.yml ,這是 Coveralls 的配置檔案,在檔案裡寫上對應的 token,如下:

1
repo_token: xxxxxxx
圖片

圖片

第三步 生成測試報告

給 Coveralls 上傳的測試報告需要有統一的 lcov 格式,大部分的單測框架都支援生成這種報告的生成,以 karma 為例

1
2
3
4
5
6
7
coverageReporter: {
    dir: path.join(__dirname, 'coverage'),
    reporters: [
        {type: 'html'},
        {type: 'lcov', subdir: 'lcov'}  // lcov
    ]
},

第四步 上傳報告

首先安裝上傳的工具,然後執行一下上傳的命令,就可以在網頁上看到了

1
2
$ npm i coveralls --save-dev
$ cat ./coverage/lcov/lcov.info | ./node_modules/.bin/coveralls

最後把徽章放到 README 裡

1
[![Coverage Status](https://img.shields.io/coveralls/react-melon/melon-core/master.svg)](https://coveralls.io/github/react-melon/melon-core)

Travis + Coveralls

運用 Travis,可以實現自動上傳程式碼覆蓋率報告,實現也很簡單:

.tarvis.yml 裡面增加一個配置

1
2
after_script:
    - npm run coveralls

.coveralls.yml 裡也增加配置,指定使用的是 Travis 的服務

1
service_name: travis-ci

package.json 裡面也定義好相關指令碼

1
2
3
4
5
"scripts": {
    "test": "./node_modules/.bin/karma start ./tool/karma.conf.js",
    "test-ci": "./node_modules/.bin/karma start ./tool/karma.ci.conf.js",
    "coveralls": "cat ./coverage/lcov/lcov.info | ./node_modules/.bin/coveralls"
},

跨瀏覽器整合測試

瀏覽器端使用的庫,在各個瀏覽器端的相容性也是非常重要的。很多專案會選擇使用 PhantomJS / jsdom 作為瀏覽器環境來執行程式碼,這樣雖然方便,但是畢竟是模擬的,無法完全替代真實的瀏覽器環境,比如 IE、FireFox 用的都不是 Webkit 的核心,IE 還有好幾個版本。 咱們的第三位劍客 SauceLabs,就提供了多重瀏覽器環境(包括 PC 端和移動端),幫助你在多個瀏覽器中自動執行指令碼。

新增子使用者

Saucelabs 註冊了一個使用者以後,沒法和 GitHub 關聯起來,它是通過建立子使用者的方法來手動關聯的,每一個專案都需要建立一個子使用者,並且有不同的 accessKey。(而且每個子使用者都需要一個不同的郵箱來註冊。。。)

通用方法

可以檢視官方的 文件

.travis.yml 中增加配置,Travis 會在執行測試指令碼之前自動安裝 Saucelabs 需要的環境

1
2
3
4
addons:
  sauce_connect:
    username: "Your Sauce Labs username"
    access_key: "Your Sauce Labs access key"

karma-sauce-launcher

karma 提供了一個調起 Saucelabs 中各個瀏覽器的外掛,可以不需要配置 Travis 就能執行,外掛庫地址:https://github.com/karma-runner/karma-sauce-launcher 裡面已經有了比較詳細的 API 文件

下面是一個 karma 配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
var _ = require('lodash');

var karmaConfig = require('./karma/config');

var customLaunchers = {
    // pc
    slChrome: {
        base: 'SauceLabs',
        browserName: 'chrome',
        platform: 'Windows 7'
    },
    slFirefox: {
        base: 'SauceLabs',
        browserName: 'firefox'
    },
    // ie family
    slIE11: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 8.1',
        version: '11'
    },
    slIE10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 8',
        version: '10'
    },
    slIE9: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        version: '9'
    },
    // mac safari
    slMacSafari: {
        base: 'SauceLabs',
        browserName: 'safari',
        platform: 'OS X 10.10'
    },
    // mobile
    slIosSafari: {
        base: 'SauceLabs',
        browserName: 'iphone',
        platform: 'OS X 10.9',
        version: '9.1'
    },
    slAndroid: {
        base: 'SauceLabs',
        browserName: 'android',
        platform: 'Linux',
        version: '4.3'
    }
};

module.exports = function (config) {

    // Use ENV vars on Travis and sauce.json locally to get credentials
    if (!process.env.SAUCE_USERNAME) {
        process.env.SAUCE_USERNAME = require('./sauce').username;
        process.env.SAUCE_ACCESS_KEY = require('./sauce').accessKey;
    }

    config.set(_.extend(karmaConfig, {
        frameworks: ['browserify', 'mocha', 'es5-shim'],
        sauceLabs: {
            'testName': 'Melon Core Unit Tests',
            'public': 'public'  // 這個配置需要設定為 public,不然我們生成的徽章就只有自己能看到了
        },
        customLaunchers: customLaunchers,
        browsers: Object.keys(customLaunchers),
        reporters: ['coverage', 'mocha', 'saucelabs'],
        singleRun: true
    }));
};

SauceLabs 配置需要注意

  • 我們需要手動給 process.env.SAUCE_USERNAMEprocess.env.SAUCE_ACCESS_KEY 賦值,accessKey 對應的是子使用者
  • 如果想提交本地的測試結果,需要新增 build 引數,用來唯一標識某一次測試(如果在 Travis 上執行就不需要特別指定,會預設使用 Travis 的構建 ID),如果沒有指定這個引數,是不會生成結果圖的
  • public 需要手動配置為 public: 'public',否則預設只有自己能看到測試結果
  • 移動端瀏覽器的 browserNameandroidiphoneversion 引數不是指的瀏覽器的版本號,而是系統的版本號

最後可以把徽章放到 README 裡

1
[![Selenium Test Status](https://saucelabs.com/browser-matrix/YOUR_USERNAME.svg)](https://saucelabs.com/u/YOUR_USERNAME)

徽章的樣式

大部分的圖示都是用了 Shield IO 的服務,它提供了一些引數可以設定徽章的樣式,以 Coveralls 為例

Coveralls Status https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=plastic

Coveralls Status https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=flat

Coveralls Status https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=flat-square

Coveralls Status https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=social

總結

我們的最終效果圖,瞬間就高端了很多。

圖片

圖片

參考文件