摘要:我已经把学习如何构建自动化跨浏览器的的单元测试列在我的年度清单中,但我每一次坐下来真正想要做的时候,我又退却了。供应商支持许多主流的单元测试框架,包括,,和。
作者:Philip Walton
译者:Yeaseon
原文链接:Learning How to Set Up Automated, Cross-browser JavaScript Unit Testing
译文仅供个人学习,不用于任何形式商业目的,转载请注明原作者、文章来源、翻译作者及链接,版权归原文作者所有。
我们都知道在多个浏览器中测试我们的代码是多么的重要。至少在我们发布第一个项目的时候,我认为我们在网络开发社区做大部分工作还是相当不错的。
我们做的不够好的工作是测试代码时每一次做出的改变。
我个人对此感到很惭愧。我已经把“学习如何构建自动化、跨浏览器的JavaScript的单元测试”列在我的年度to-do清单中,但我每一次坐下来真正想要做的时候,我又退却了。虽然我肯定这一部分原因是因为我的懒惰,同时我认为这也是由于缺乏良好的可用信息在这个主题上。
有许多工具和框架(例如 Karma)宣称“要使自动化的JavaScript测试变得简单”,但以我的经验看来这些工具引入的复杂性比他们摆脱的复杂性更多。在我的工作经验中,如果你是一个专家这些工具“能工作”的很好,但对于一个初学者是很糟糕的。我想要真正了解的是这个流程是如何在引擎中工作的,以便在它出现问题的时候(总会出现问题的),我能解决它。
对我来说,充分了解这些是如何工作的最好方法就是尝试从头开始重新创建它。所以我决定去构建我自己的测试工具,然后把我的所学分享到社区中。
手工测试流程在我解释自动化过程之前,我认为最重要的是确保我们都在同一页面上进行手工测试工作。
毕竟,自动化是关于使用机器来关闭负载的重复部分的现有工作流程。如果你在充分理解手工过程之前尝试去开始自动化,它也不会像你理解了自动化过程一样。
在手工过程中,你写了一个你的测试文件,它可能看起来像是:
var assert = require("assert"); var SomeClass = require("../lib/some-class"); describe("SomeClass", function() { describe("someMethod", function() { it("accept thing A and transforms it into thing B",function() { var sc = new SomeClass(); assert.equal(sc.someMethod("A"), "B"); }); }); });
这个例子用了Mocha和Node.js 资源模块,但是重要的不是你是用的测试库或者断言库,它可以使任意一个。
在Mocha中运行Node.js,在你终端通过命令行你就能运行这个测试:
mocha test/some-class-test.js
你需要一个带有标签的HTML文件加载这段脚本,才能在浏览器运行这个测试,浏览器并不认识require声明,你需要一个像是browserify或者webpack的模块打包工具去解决这些依赖。
browserify test/*-test.js > test/index.js
像是browserify或是webpack的模块打包工具的好处就是它能整合你的所有测试(也包括依赖)到一个单一的文件中,这样就能很容易加载到你的测试页面。
一个用Mocha写的典型测试文件看起来像是这样的:
Tests
做一些事情,像下面这样:
在上面的代码和默认的Mocha模板中唯一不同的是分配给测试结果的变量名,就像Sauce Labs期望的格式一样叫做window.mochaResults。因为这个新的代码不会影响正在浏览器中运行的手工测试,你不妨就开始使用它作为默认的Mocha模板。
再次强调一点,当Sauce Labs“运行”你的测试时,它并没有做任何事,它只是单纯的访问一个页面,等到发现一个window.mochaResults对象,然后记录下这个结果。
确定你的测试通过还是失败
StartJS Unit Tests 方法会告诉Sauce Labs去挨个在你指定的浏览器/平台运行测试,但是它不会返回测试的结果。
它返回所有工作队列中的ID,响应看起来像是这样的:
{ "js tests": [ "9b6a2d7e6c8d4fd2afeeb0ff7e54e694", "d38688ec7256497da6966f4523ddee76", "14054e68ccd344c0bed77a798a9ce1e8", "dbc54181f7d947458f52201ea5fcb901" ] }
要确定你测试通过还是失败,你要调用GetJS Unit Status方法,它接手一个工作队列并且返回当前每个工作的工作状态。
这个想法是你要定期调用这个方法,知道所有工作都完成。
request({ url: `https://saucelabs.com/rest/v1/${username}/js-tests/status`, method: "POST", auth: { username: process.env.SAUCE_USERNAME, password: process.env.SAUCE_ACCESS_KEY }, json: true, body: jsTests, // The response.body from the first API call. }, (err, response) => { if (err) { console.error(err); } else { console.log(response.body); } });
响应的结果看起来像是这样:
{ "completed": false, "js tests": [ { "url": "https://saucelabs.com/jobs/75ac4cadb85e415fae957f7811d778b8", "platform": [ "Windows 10", "chrome", "latest" ], "result": { "passes": 29, "tests": 30, "end": {}, "suites": 7, "reports": [], "start": {}, "duration": 97, "failures": 0, "pending": 1 }, "id": "1f74a237d5ba4a47b5a42570ae1e7999", "job_id": "75ac4cadb85e415fae957f7811d778b8" }, // ... the rest of the jobs ] }
一旦response.body.complete属性值为true,就表示你的测试已经运行完成,然后你就可以通过检查每个工作流程的通过还是失败。
本地访问测试我已经解释过Sauce Labs“运行”你的测试通过访问一个URL。当然,这意味着这个URL必须是公开在网络上可访问的链接。
有一个问题就是如果你的测试服务启动在localhost。
有很多解决这个问题的方案,包括Sauce Connect(官方推荐的一种),这是一个由Sauce Labs创建的代理服务器,在Sauce Labs虚拟机和本地主机之间开启一个安全连接。
Sauce Labs是处于安全性的考虑被设计的,并且使得外部无法获得你的代码。它的缺点就是十分复杂的设置与使用。
如果你的代码涉及到安全性,它可能值得你去弄清楚Sauce Labs;如果不是的话,有许多相似的方案去更简单的解决这个问题。
我选择的方案是ngrok
ngrok
ngrok是一个用于创建安全隧道连接工具。它给你一个公共的URL到web服务器运行在你的本地机器上,确切的是你需要运行测试在Sauce Labs上。
如果你在虚拟机上进行开发或手动测试,你可能已经听说过ngrok,如果没有,那你应该去查阅一下了,它是极其有用的工具。
在你的机器上安装ngrok像是下载二进制文件,然后添加到你的路径中一样简单;如果你将会在Node中使用ngrok,你也需要通过npm安装它。
npm install ngrok
你可以用下面的代码以编程方式从Node中开始ngrok进程:
const ngrok = require("ngrok"); ngrok.connect(port, (err, url) => { if (err) { console.error(err); } else { console.log(`Tests now accessible at: ${url}`); } });
只要你有一个公共的URL能访问你的测试文件,用Sauce Labs跨浏览器测试你的本地代码会变得十分容易。
整合碎片化这篇文章包含了很多主题,给人的印象是自动化的,跨浏览器的JavaScript单元测试是复杂的。但情况并非如此。
我从我的角度来看这篇文章-当我试图去解决这个问题。然后回顾我之前的经验,真正复杂的是缺少解决整个流程如何工作的有效信息,和怎么样把所有的整合到一起。
一旦你了解了所有的步骤,它很简单。总结:
最初的手工流程
写一个测试然后创建一个单一的HTML页面去运行它。
在本地的一个或者两个浏览器中运行这个测试,确保它能工作。
增加自动化流程
创建一个开源的Sauce Labs账号,获得一个用户名和访问权限。
更新你的测试页面源码,以便Sauce Labs能通过JavaScript全局变量读取测试结果。
用ngrok给你的本地测试页面创建一个安全隧道,这样就能在互联网公开的访问了。
调用StartJS Unit Tests接口方法列出你想测试的浏览器/平台。
定时调用GetJS Unit Test Status方法知道工作完成。
报告结果。
使测试变得更容易我知道这篇文章开头我谈了很多关于你不需要一个框架来做自动化,跨浏览器的JavaScript单元测试,我现在仍然坚信这个。然而,尽管每一步都很简单,你可能不想在每次都为项目编写代码。
我想给我的很多老项目增加自动化测试,所以对我来说打包这些逻辑到我的模块中是很有意义的。
我推荐你尝试实现一个你自己的框架,这样你就可以完全理解它是如何工作的,但如果你没有时间并且还想快速建立一个测试,我建议你使用我创建的库Easy Sauce。
Easy SauceEasy Sauce是一个Node包和一个命令行工具,现在我为我想做跨浏览器测试的每一个JavaScript项目都使用这个包。
easy-sauce 命令可以设置你的HTML测试文件的路径(默认是/test/)、开启本地服务的端口(默认是1337端口)和一系列的浏览器/平台进行测试。easy-sauce将会在Sauce Lab’s selenium cloud运行你的测试,将日志打印在控制台并通过合适的状态码告知你测试是否通过。
npm包使它变得更方便,easy-sauce将会默认在package.json文件中查找配置选项,所以你不必分别的存储它们。好处是用户更加明确的知道你的包支持浏览器/平台。
对于easy sauce完整的用法介绍,请查看Github文档。
最后,我想强调的是我专门建立这个项目来解决我的需要。虽然我认为这个项目对于很多开发人员都十分有用,但我没有计划把它变成一个功能齐全的测试解决方案。
结语在这篇文章的开始,我写下了一系列的需求。在Easy Sauce的帮助下,我正努力的在任何项目中满足这些需求。
如果你还没有为你的项目做自动化、跨浏览器的JavaScript单元测试,我鼓励你给Easy Sauce一个尝试的机会。即使你不想用Easy Sauce,你至少应该了解你自己的需求或更好地了解现有的工具。
Happy testing!
如果你能看到这里,很感谢你的耐心阅读。
这是我翻译的第一篇技术文档,自身水平有限,所以翻译总有不当与疏漏,如有发现还请您耐心评论指出。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/86390.html
摘要:不论你是在写浏览器端还是后端的,总存在那么一个问题我该使用什么单元测试库去确保我的代码如预期的运行呢总是有那么一些流行的框架可供选择。在中仍然流行,并且拥有来自许多地方性的支持。如果你的测试使用它,直到调用了才能通过。 不论你是在写浏览器端javascript还是后端的nodejs,总存在那么一个问题:我该使用什么单元测试库去确保我的代码如预期的运行呢?总是有那么一些流行的框架可供选择...
摘要:避免脆弱的基类问题。红牌警告没有提到上述任何问题。单向数据流意味着模型是单一的事实来源。单向数据流是确定性的,而双向绑定可能导致更难以遵循和理解的副作用。原文地址 1. 你能说出两种对 JavaScript 应用开发者而言的编程范式吗? 希望听到: 2. 什么是函数编程? 希望听到: 3. 类继承和原型继承的不同? 希望听到 4. 函数式编程和面向对象编程的优缺点? ...
摘要:首先安装单元测试环境使用模块来模拟定义的模型。根据删除这是单元测试的最后一小节。需要根据需求和单元测试用例来编写应用逻辑,使我们的程序更加稳定。我们会运行自动测试用例,一直重构,直到所有单元测试都通过。 本文转载自:众成翻译译者:文蔺链接:http://www.zcfy.cc/article/746原文:https://semaphoreci.com/community/tutoria...
摘要:首先安装单元测试环境使用模块来模拟定义的模型。根据删除这是单元测试的最后一小节。需要根据需求和单元测试用例来编写应用逻辑,使我们的程序更加稳定。我们会运行自动测试用例,一直重构,直到所有单元测试都通过。 本文转载自:众成翻译译者:文蔺链接:http://www.zcfy.cc/article/746原文:https://semaphoreci.com/community/tutoria...
阅读 2962·2021-09-22 14:59
阅读 1754·2021-09-22 10:02
阅读 2077·2021-09-04 16:48
阅读 2152·2019-08-30 15:53
阅读 2934·2019-08-30 11:27
阅读 3387·2019-08-29 18:35
阅读 879·2019-08-29 17:07
阅读 2648·2019-08-29 13:27