成为一名 JavaScript 开发人员是一个激动人心的时刻;技术已经成熟,网络浏览器更加标准化,每天都有新的东西可以玩。JavaScript 已经成为一种约定俗成的语言,Web 是当今真正的开放平台。我们已经看到了单页 web 应用的兴起,诸如 Backbone.js. js 和安古拉 JS 等 MVC 框架的激增,使用 Node.js 在服务器上使用 JavaScript,甚至使用诸如 PhoneGap 等技术完全使用 HTML、JavaScript 和 CSS 创建的移动应用。
从处理 HTML 表单的不起眼的开始,到今天的大规模应用,JavaScript 语言已经走了很远,有了它,许多工具已经成熟,可以确保您可以使用它获得与任何其他语言相同的质量水平。
这本书是关于让你控制你的 JavaScript 开发的工具。
处理客户端 JavaScript 代码时有很多的复杂之处;显而易见的一点是,您无法控制客户端的运行时。在服务器上,你可以运行特定版本的 Node.js Server,但是你不能强迫你的客户端运行最新版本的 Chrome 或者 Firefox。
JavaScript 语言由 ECMAScript 规范定义;因此,每个浏览器都可以有自己的运行时实现,这意味着它们之间可能有小的差异或错误。
除此之外,你还有语言本身的问题。JavaScript 是 Brendan Eich 在网景公司的管理压力下,在短短 10 天内开发出来的。尽管它在简单性、一流的功能和对象原型方面做得很好,但它也引入了一些问题,试图使语言具有延展性并允许它发展。
每个 JavaScript 对象都是可变的;这意味着您无法阻止一个模块覆盖其他模块。下面的代码说明了覆盖全局console.log
函数是多么简单。
console.log('test');
>> 'test'
console.log = 'break';
console.log('test');
>> TypeError: Property 'log' of object #<Console> is not afunction
这是语言设计上的一个有意识的决定;它允许开发人员修补和添加语言中缺失的功能。但考虑到这样的权力,犯错误相对容易。
该语言的一个更新版本引入了 Object.seal
函数,该函数防止对任何被调用的对象进行进一步的更改。但它目前的支持并不广泛;它只在 Internet Explorer 9 上推出,目前在 Opera 上错过了。
另一个问题是 JavaScript 如何处理类型。在其他语言中,像'1' + 1
这样的表达式可能会引发错误,在 JavaScript 中,由于一些非直观的类型强制规则,上面的代码会导致'11'
。但主要问题在于它的不一致性;在乘法运算中,字符串被转换成数字,所以'3' * 4
,实际上是12
。
这可能会导致一些难以发现的大表达式问题。假设您有一些来自服务器的数据,虽然您期望的是数字,但是有一个值是字符串:
var a = 1, b = '2', c = 3, d = 4;
var result = a + b + c * d;
上面的结果值是'1212'
,一个字符串。
这只是开发者面临的两个常见问题。在整本书中,您将应用最佳实践并编写测试,以确保您不会陷入这些和其他陷阱。
Jasmine 是一个小小的行为驱动开发框架,由 Pivotal 实验室的人创建,允许你编写自动化的 JavaScript 单元测试。
但是在我们能够更进一步之前,首先我们需要得到一些基础知识,从什么是测试单元开始。
测试单元是测试应用代码的功能单元的一段代码。但是有时候理解一个功能单元可以是什么是很棘手的,所以为此,丹诺斯以 行为驱动开发 ( BDD )的形式提出了一个解决方案,这是对 测试驱动开发 ( TDD )的重新思考。
在传统的单元测试实践中,开发人员在测试过程中没有关于如何开始、测试什么、测试应该有多大,甚至如何调用测试的指导方针。
为了解决这些问题,丹将标准敏捷构建中用户故事的概念作为如何编写测试的模型。
例如,音乐播放器应用可以有一个接受标准,如:
给定一个玩家,当歌曲已经暂停那么应该表示该歌曲当前正在暂停。
如您所见,这个接受标准是按照一个基本模式编写的:
- 给定【初始上下文】
- 当【事件发生】时
- 然后【保证一定胜负】
在 Jasmine 中,这转化为一种非常有表现力的语言,允许以反映实际业务价值的方式编写测试。作为 Jasmine 测试单元的上述验收标准是:
describe("Player", function() {
describe("when song has been paused", function() {
it("should indicate that the song is paused", function() {
});
});
});
您可以看到该标准如何很好地翻译成 Jasmine 语法。在下一章中,我们将详细介绍这些函数是如何工作的。
对于 Jasmine,就像其他 BDD 框架一样,每个验收标准直接转化为一个测试单元。因此,每个测试单元通常被称为一个 规范,规范的简称。在本书的过程中,我们将使用这个术语。
Jasmine 的入门其实很简单。在http://pivotal.github.io/jasmine/打开 Jasmine 网站,下载独立版本。
而在 Jasmine 网站,你可能会注意到它实际上是一个实时页面,执行其中包含的规范。这是因为 Jasmine 框架的简单性,允许它在最多样化的环境中执行。
下载发行版并解压缩后,您可以在浏览器上打开SpecRunner.html
文件。它将显示示例测试套件的结果(包括我们之前向您展示的验收标准):
SpecRunner.html 打开了浏览器
这个SpecRunner.html
文件是一个 Jasmine 浏览器的 spec runner。它是一个简单的 HTML 文件,引用了 Jasmine 代码、源文件和测试文件。出于惯例,我们将这个文件简称为 runner 。
通过在文本编辑器上打开它,您可以看到它有多简单。这是一个小的 HTML 文件,引用了 Jasmine 的源代码:
<script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-html.js"></script>
引用源文件:
<!-- include source files here... -->
<script type="text/javascript" src="src/Player.js"></script>
<script type="text/javascript" src="src/Song.js"></script>
参考规范文件:
<script type="text/javascript" src="spec/PlayerSpec.js"></script>
并包含一个小的 Jasmine 引导代码:
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
在第 8 章、打造自动化中,我们将深入了解如何定制这款跑者,但是对于现在你可以看到:
- 它配置了一个
jasmine.HtmlReporter
,在 HTML 上报告测试结果 - 它在
window.onload
上增加了一个回调 - 一旦窗口被加载,它就通过
jasmineEnv.execute()
执行 Jasmine 测试套件
重要的是,您要看一看这段代码,了解 Jasmine 提供的灵活性;您可以看到它没有依赖关系,即使结果呈现在一个 HTML 文件上,也可以通过切换 reporter 来轻松更改:
jasmineEnv.addReporter(new jasmine.TerminalReporter());
然后在一个 无头浏览器上运行同样的代码,比如 PhantomJS ,并将结果写在控制台上。
无头浏览器是没有图形用户界面的浏览器环境。它既可以是一个实际的浏览器环境,比如使用 WebKit 渲染引擎的 PhantomJS,也可以是一个模拟的浏览器环境,比如 Envjs。
但是 Jasmine 也可以用来测试服务器代码,在 Node.js 运行时使用相同的报告程序。
这种 Jasmine 的灵活性非常惊人,因为您可以使用同一个工具来测试各种 JavaScript 代码。
在本章中,您已经看到了测试 JavaScript 应用背后的一些动机。我向您展示了 JavaScript 语言的一些常见缺陷,以及 BDD 和 Jasmine 如何帮助您编写更好的测试。
您也已经看到了下载和开始使用 Jasmine 是多么容易。在下一章中,你将学习如何在 BDD 中思考并编写你的第一个规范。