开发业务代码的时候,我们总能发现一些通用的功能。这时候,作为一个在互联网时代富有分享精神的程序员,就会想要把项目开源出去,让更多的小伙伴去使用,偶尔可能会有大神评论,能学到很多。 在 GitHub 上, README 是最先让人看到的,一些应用广泛的项目的 README ,除了非常详细的文字介绍,还常常会带有很多小徽章,比如 Vue
的这个 README 的开头:
这些徽章 (badage) 展示了代码的测试覆盖率、构建状态、在各个浏览器中的运行情况,这会让项目显得更加专业和有说服力。本文以笔者集齐了一套徽章的亲身经历,总结了过程中的主要流程和一些踩到的坑,欢迎大家补充,让我们的项目流行起来!
首先,安利一下我们开发的一个基于 React 和 Material Design 的组件库 Melon,欢迎大家使用,如果能加个星,提个 pr 就更欢迎了。
靠人工来保证项目的维护总是不出差错是不靠谱的,人总有健忘和糊涂的时候,尤其是当项目越来越复杂时,一个人甚至可能无法全部了解项目的全部逻辑,这时我们就要依靠测试来保证项目的可靠性,这里的测试包括但不限于,单元功能测试,UI 测试,兼容性测试等等。
关于单测框架已经有很多教程和文档,一个测试体系大体应该包含四部分
其中,jasmine
是一个比较完整的测试框架,还自带了丰富的断言函数,在编写测试用例的时候不再需要单独去引用断言库。以 Melon 项目为例,笔者使用的是 karma+jasmine+istanbul
的组合,由于这是基于 React 的库,并且代码是 ES6 编写的,因此需要加上 browserify
babelify
这些插件。
Melon 项目 karma 配置示例: https://github.com/react-melon/melon-core/blob/master/tool/karma/config.js
有了一整套测试体系,编写完代码的测试用例,就可以开始应用下面的三个工具帮你生成徽章了
持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
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)
|
写完整单元测试代码是维护一个快速迭代项目不出差错的有效方法,代码覆盖率报告可以为编写测试程序提供参考。通过一些工具,还可以及时的把你的代码的测试情况及时的反馈给用户,让用户感知你的测试是否完备。
第二位剑客登场: Coveralls 它可以帮你生成一个展示代码覆盖率的徽章:
打开 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,可以实现自动上传代码覆盖率报告,实现也很简单:
在 .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 提供了一个调起 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_USERNAME
和 process.env.SAUCE_ACCESS_KEY
赋值,accessKey
对应的是子用户build
参数,用来唯一标识某一次测试(如果在 Travis 上运行就不需要特别指定,会默认使用 Travis 的构建 ID),如果没有指定这个参数,是不会生成结果图的public
需要手动配置为 public: 'public'
,否则默认只有自己能看到测试结果browserName
是 android
或 iphone
,version
参数不是指的浏览器的版本号,而是系统的版本号最后可以把徽章放到 README 里
1
|
[![Selenium Test Status](https://saucelabs.com/browser-matrix/YOUR_USERNAME.svg)](https://saucelabs.com/u/YOUR_USERNAME)
|
大部分的图标都是用了 Shield IO 的服务,它提供了一些参数可以设置徽章的样式,以 Coveralls 为例
https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=plastic
https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=flat
https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=flat-square
https://img.shields.io/coveralls/react-melon/melon-core/master.svg?style=social
我们的最终效果图,瞬间就高端了很多。
一个靠谱的前端开源项目需要什么?