持续集成之测试篇

持续集成单元测试(unit)karmaKarma 是Google开源的一个基于Node.js 的 JavaScript 测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到 CI (Continuous integration)工具,也可和其他代码编辑器一起使用。 我们测试用的无界面浏览器phantomjs。测试框架使用mocha和chai。 以下是我们项目中使用的主要配置信息: /** * 测试启动的浏览器 * 可用的浏览器:https://npmjs.org/browse/keyword/karma-launcher */browsers: ['PhantomJS'],/** * 测试框架 * 可用的框架:https://npmjs.org/browse/keyword/karma-adapter */frameworks: ['mocha', 'chai'],/** * 需要加载到浏览器的文件列表 */files: [ '../../src/dcv/plugins/jquery/jquery-1.8.1.min.js', '../../src/dcv/plugins/common/mock.min.js', '../../src/dcv/plugins/common/bluebird.min.js', '../../src/dcv/javascripts/uinv.js', '../../src/dcv/javascripts/uinv_util.js', '../../src/dcv/javascripts/browser/uinv_browser.js', 'specs/validators.js'],/** * 排除的文件列表 */exclude: [],/** * 在浏览器使用之前处理匹配的文件 * 可用的预处理: https://npmjs.org/browse/keyword/karma-preprocessor */preprocessors: { //报告覆盖 "../../src/dcv/javascripts/**/*.js": ["coverage"]},/** * 使用测试结果报告者 * 可能的值: "dots", "progress" * 可用的报告者:https://npmjs.org/browse/keyword/karma-reporter */reporters: ['spec', 'coverage'],/** * 使用reporters为"coverage"时报告输出的类型和那目录 */coverageReporter: { type: 'html', dir: 'coverage/'},/** * 服务端口号 */port: 9876,/** * 启用或禁用输出报告或者日志中的颜色 */colors: true,/** * 日志等级 * 可能的值: * config.LOG_DISABLE //不输出信息 * config.LOG_ERROR //只输出错误信息 * config.LOG_WARN //只输出警告信息 * config.LOG_INFO //输出全部信息 * config.LOG_DEBUG //输出调试信息 */logLevel: config.LOG_INFO,/** * 启用或禁用自动检测文件变化进行测试 */autoWatch: true,/** * 开启或禁用持续集成模式 * 设置为true, Karma将打开浏览器,执行测试并最后退出 */// singleRun: true,/** * 并发级别(启动的浏览器数) */concurrency: Infinity在package.json中配置如下: ...

June 20, 2019 · 5 min · jiezi

关于 E2E 测试

上一篇文章发布后,竟然收获到一些同学的注意,实在是意外之喜。不过我也发现,很多同学对 E2E 测试不够了解,正好我厂的产品也没做到能作为商用版发布的程度,所以这篇再来聊聊 E2E 测试吧。本文的测试均指自动化测试。E2E,是“End to End”的缩写,可以翻译成“端到端”测试。它模仿用户,从某个入口开始,逐步执行操作,直到完成某项工作。与单元测试不同,后者通常需要测试参数、参数类型、参数值、参数数量、返回值、抛出错误等,目的在于保证特定函数能够在任何情况下都稳定可靠完成工作。单元测试假定只要所有函数都正常工作,那么整个产品就能正常工作。相对来说,E2E 测试并没有那么强调要覆盖全部使用场景,它关注的是 一个完整的操作链是否能够完成。对于 Web 前端来说,还关注 界面布局、内容信息是否符合预期。比如,登陆界面的 E2E 测试,关注用户是否能够正常输入,正常登录;登陆失败的话,是否能够正确显示错误信息。至于输入不合法的内容是否处理,没有很大的关系。Web 前端 E2E 测试的现状Web 前端 E2E 自动化测试开展得不好。在我从业的这十几年里,大部分产品的前端 E2E 测试都交给测试人员手工完成。我们稍稍分析一下,大概有三个原因:1. 测试环境不好搭单元测试也好、接口测试也好,测试环境都很容易搭建。然而 Web 前端测试如果想达到目的,需要完整的桌面操作系统和浏览器环境,这种面向普通用户的软件对自动化工具并不友好。对系统要求也比较高,很难整合到开发测试工具链档中。解决方案当然是有的,目前最流行的应该是 Selenium WebDriver。不过对于小公司、小团队来说,在并不丰富的资料中摸着石头过河实在不够经济,而且,还有接下来的两个问题。2. 测试不好写。目前的 Web 前端 E2E 测试工具局限于 XPath 技术栈。大家用选择器查找 DOM 节点,校验其属性和内容,接着进行交互。这样做导致一个必然后果:写测试的人员对页面的 DOM 结构必须了如指掌,才能用准确目标元素。同时,在这个技术环境下写就的测试用例,一旦 DOM 结构出现变化,就要大规模的修改,甚至重写。工作量很大,而且存在一些不稳定因素。跟某团队 Leader 聊天,他就很担心漫长的迭代过程中,DOM 结构变化导致测试用例失效,继而引发项目排期混乱。结果,Web 前端 E2E 测试用例的只能由前端用 JS 写,工作量大,维护负担重,且存在一些风险。大家都不愿意写。3. 有些东西不好测随着用户对产品的要求水涨船高,页面逻辑越来越复杂,功能越发依赖 Ajax,甚至和后端彻底分离,成为单页应用(SPA)。这类产品与传统的静态页服务不同,我们没法侦听 DOMReady 事件,也就难以找到合适的时间点启动测试。早些时候,我们只能依靠 setInterval() 轮询。如今,通过 Puppeteer 或者浏览器扩展都可以监听网络连接,可以根据当前保持的连接数来判断请求是否完成。不过这些做法仍然存在不小的实施难度。4. 预期收益一般我跟很多技术老大聊过。大家的回答都是:没写,没空,招测试。在加班成为常态的今天,在“看得到”的工作之外,再去做这些“看不到”的工作,实在有些吃力不讨好。另一方面,测试写得少,覆盖率跟不上,还是得招测试,人工测试。恶行循环就此产生:不想写导致没测试;那就招测试人员;有了专职测试我还写什么测试……所以大家都不写测试了。对于中等以上规模的技术团队,招几个测试也还行。对于整个公司就只有几个人的创业团队来说,大多数时候只能裸奔……更好的 Web 前端 E2E 测试工具行文至此,结论就很明显了:我们需要全新的、更高级的 Web 前端 E2E 测试工具。这个工具需要同时满足:1. 有效可以准确地描述 UI 的结构可以尽量全面的模拟用户真实操作覆盖多种操作系统、适配各种浏览器2. 使用成本低测试用例应该尽量简短,用最少的代码描述出 UI,完成交互。测试用例应该和 DOM 实现解耦,用的尽量久,能不改就不改。测试用例应该让所有人都学得会,写得通3. 提高开发效率应该提供方便易用的编写、测试环境,让用户可以轻松上手需要能够和常见的 CI 系统集成我厂的解决方案最后回到我厂。我们设计了一个全新的语言用来描述 UI,叫做 Navlang。我们可以用它描述各元素的相对位置,操作元素进行交互。它是一个描述性语言,只包含很简单的逻辑——实际上 E2E 测试也不需要多复杂的逻辑,跑不通就是挂了,跑通了就没问题。这样一来,任何人,只要经过简单的培训,都可以写出正确的测试用例。(HTML 就是最好的例子。前端很多都是页面仔出身,比如我,相信大家对这类语言的易学易用都有所了解。)因为是语言,所以它可以写成代码,可以被版本管理;因为是新的抽象,所以它不跟 DOM 实现耦合,可以被反复使用,几乎没有维护成本。(只有界面变化才需要修改测试用例,此时无论如何都要修改测试用例)目前这个工具已经在我厂的开发体系中工作将近一年,为我厂产品的稳定做出了非常重大的贡献。功能化之外,我们也在作产品化和商品化的努力。目前已经基本完成浏览器扩展功能,让普通用户可以通过浏览器扩展编写和运行测试。接下来,我们还会提供基于 Node.js 的测试工具框架,帮助大家将测试集成到现有的 CI 系统当中。未来,这款产品会服务广大小型公司和小型团队,帮助大家提升 Web UI 测试的效率。好了,敬请期待下周的 Navlang 介绍吧。 ...

March 15, 2019 · 1 min · jiezi

[缘起] 前端 E2E 测试的困境

与其它自动化测试不同,前端的e2e测试一直是个老大难问题,难点主要在于 如何描述测试。自动化测试的核心是检查特定输入能不能得到符合预期的结果。对于单元测试和 API 测试来说,“特定输入”就是函数或者接口的参数,结果也是当前语言的数据类型或者通用的比如 JSON,二者一方面好描述,另一方面好验证。写起来就没什么难度。比如sum(a, b) { return a + b;}要验证输入 1 和 2,返回 3,则可以写成:const assert = require(‘assert’);describe(‘sum’, function() { it(‘should equal’, function() { assert.equal(sum(1, 2), 3); });});这里输入输出都很容易描述,所以自动化测试就没什么难度。但是 UI 测试并非如此。UI 是做给用户看的,所以,一个 UI 测试应该写成这种形式(这里拿一个类似于活动行的应用来举例子):打开应用首页呈现出活动列表点击列表中的任一项进入活动详情页点击报名按钮登记个人信息点击付费按钮完成付费看到报名成功的信息这个过程当中用户的操作,很难和程序当中的抽象产物,比如按钮、列表等产生关联。操作的结果,“进入下一页”,也很难进行进一步的校验。所以在之前的生产实践中,大家喜欢用选择器来进行 E2E 测试,代表产品有 Cypress 和 Nightwatch。我觉得,这里一方面有 jQuery 带来的使用习惯延续和思维定势;另一方面,借助 XPath,找到特定元件,进行交互操作和校验元素几乎是大家唯一的选择。使用 CSS 选择器的方案并不完美,比如:选择器本身,和 UI 视图可能并没有强关联,写出来的测试可读性不强,一段时间之后回头去看,很可能会看不懂。HTML 的 DOM 结构并不稳固,随着功能增减版本迭代经常发生变化,这个时候我们就要跟着修改测试用例。DOM 结构不能反应视图的真实状态,很可能会出现虽然测试通过,但实际上在用户眼里仍然是错误的表现。那么,说了这么多不容易、其它方案的不完美,我的解决方案又是怎么样的呢?这里请容许我卖一下关子,下次再介绍由我厂 OpenResty Inc. 打造的前端自动化工具 Navlang。大家好,我是 Meathill,目前在 OpenResty Inc. 负责前端开发工作。今年我会利用业余时间,介绍我厂在前端方面的工作,包括各种垂直领域,比如自动化、DevTool protocol、插件开发、Vue、CodeMirror、组件化等等,内容包括进展、经验、心得、踩坑、产品等。欢迎大家关注本专栏,也欢迎大家光临我的博客:山维空间。如果你有任何疑问问题都可以在 SF 和我的博客上向我发问,我一定尽量答复。

February 4, 2019 · 1 min · jiezi