如前所述,上面的测试用例对象是为JsTestDriver写的,一个从谷歌出来的Javascript测试框架和测试运行器。把JsTestDriver从(产品)包中分离出来才是运行测试的正路。相比于标准的HTML文件加载源和测试,JsTestDriver运行一个可以帮你同时立即在多个浏览器上执行测试的服务器。理解它是如何工作的最有效的办法就是看清的行动。
假设该jQuery插件在src/difference_in_words.jquery.js,测试用例在test/difference_in_words_test.js。为了运行这个测试,我们在项目的根目录添加一个配置文件jsTestDriver.conf。它包括下面的内容:
[plain] view plaincopy1. server: http://localhost:4224
2.
3. load:
4. - src/*.js
5. - test/*.js
现在下载JsTestDriver.jar的最新版。同时需要安装Java。然后在命令行中执行如下命令(如果是Windows,就是cmd.exe):
1. java -jar JsTestDriver-1.2.2.jar --port 4224
现在你就已经在你机器上打开了一个JsTestDriver服务器。下一步是打开一个链接为http://localhost:4224/capture的浏览器,它让浏览器转入懒测试运行从属(which will turn the browser into an idle test runningslave)。在你所有能用的浏览器上做同样的事。然后打开一个命令行,cd进入项目目录并键入:
java -jar JsTestDriver-1.2.2.jar --tests all
很快你应该能够看到一些输出:JsTestDriver在所有可用浏览器上运行的两个测试,并显示是否通过。恭喜你,你已经在多个浏览器上自动测试了!如果你的机器可以通过网络使用其他设备访问,你也可以使用这个服务器测试其他平台(OS X, Windows,Linux),你的iPhone, Android电话和其他移动设备。并且你只要在一个命令行就可以全部验证它们。多么令人激动呀!
JsTestDriver不是你自动化测试的唯一选择。如果你不喜欢它的断言框架,你也可以运行用QUnit, YUI Test 和 Jasmine写的测试。另外,雅虎YETI,一个只对YUI的类似的工具, Nicholas Zakas最近发布了YUI TestStandalone,包括了基于SeleniumWeb Driver的类似的运行器。
可测试性:用测试改善你的代码
现在,你可能希望开始实现大量节省时间的单元测试就可以了,特别是对通常预期在多个环境运行得很好的JavaScript。单元测试不仅相比手工调试和猴子补丁(monkey patching)节省大量的时间,而且可以提高你的信心、快乐和生产力。
现在已经决定开始写单元测试,你可能想知道如何开始。明显的答案是为现有的代码写一些测试。不幸的是,那结果往往是现实很困难。部分原因是写测试需要实践,而且前几个(测试)通常很难正确,甚至只是输入(正确)。然而,为什么为现有的代码写测试很困难常常还有另外一个原因:代码不是和测试思想一起写的,通常不是很测试友好的。
可测试性的例子:计算时间差
“可测试性”是特定接口的测试友好方面的度量。一个测试友好的接口使所有对它关注的部分能方便的从外部存取,不需要为测试任何一个给定部分的API而建立无关的状态。换句话说,可测试性是和良好设计有关的,松耦合、高内聚的,这只是花哨方法说对象不应该依赖于太多其他对象并且每个对象/函数只做好一件事。
作为一个可测试性的例子,我们再来看我们的jQuery插件。在前两个单元测试中,我们希望确保对8天前的日期使用插件,结果是字符串“1 weekago”,并且另一个日期的结果是一个更详细的字符串表示。注意,这两个测试没有任何DOM元素操作,虽然我们不得不创建一个对象以测试日期差计算和人类友好的描述字符串。
这个jQuery插件明显比它本来难以测试,主要原因是它做了不止一件事情:计算日期差,生成两个日期差的人类易读的描述,并且从DOM节点的innerHTML抓取日期和更新它 。
要解决这个问题,考虑下面的代码,它是同样的插件的另一种实现:
[javascript] view plaincopy1. var dateUtil = {};
2.
3. (function () {
4. var units = {
5. second: 1000,
6. minute: 1000 * 60,
7. hour: 1000 * 60 * 60,
8. day: 1000 * 60 * 60 * 24,
9. week: 1000 * 60 * 60 * 24 * 7,
10. month: 1000 * 60 * 60 * 24 * 30
11. };
12.
13. function format(num, type) {
14. return num + " " + type + (num > 1 ? "s" : "");
15. }
16.
17. dateUtil.differenceInWords = function (date) {
18. // return correct string
19. };
20.
21. jQuery.fn.differenceInWords = function () {
22. this.each(function () {
23. var datetime = this.getAttribute("datetime");
24. this.innerHTML = dateUtil.differenceInWords(new Date(datetime));
25. });
26. };
27. }());
和前面的代码相同,只是重新整理了。现在有两个公开函数:jQuery插件和新的接受一个日期并返回一个人类可读的描述多长时间之前的一个字符串的dateUtil.differenceInWords。还不完美,但我们已经把它分成了两个关注点。现在jQuery插件只负责用人性化的字符串替换元素的innerHTML ,而新函数只负责计算成正确的字符串。虽然旧的测试仍然能通过,但测试应该针对新接口简化。
[javascript] view plaincopy1. TestCase("TimeDifferenceInWordsTest", {
2. setUp: function () {
3. this.date8DaysAgo = new Date(new Date() - 8 * day);
4. var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;
5. this.date3DaysAgo = new Date(new Date() - diff);