你当然是测试你的代码。没有写出相当数量的代码后不运行一下就直接丢到产品中。在本文中我对你是如何测试的进行质疑。如果你不是已经尽可能的多的自动化测试,为生产力和信息提升做好准备吧。
一句话的警告:我将在本文中谈论单元测试和测试驱动开发(TDD),如果你已经得出结论:下面的任何理由对你都不适合,那么请继续阅读,或者至少阅读从我为什么要关心?到最后:
我使用一个库,如jQuery,它保证我的代码正确的工作
测试是一个对专业人员的高级的实践,不适合我
测试太费时间,我只想写产品代码
不同的目的,不同的测试
测试意味着很多事,如何把测试做的最好依赖于一个详尽的测试目标。这里有一些可能会在你的应用中遇到的测试的例子:
易用性测试
性能测试
一致性/回归测试
在本文中,我们专注于一致性和回归测试。换句话说,是那种保障代码做它应该做的事,并且没有缺陷。绝大多数情况下,不能证明绝对没有缺陷。我们能做的就是保证有效的减少缺陷的数量,并且防止已知缺陷爬回到我们的代码中。
如何发现缺陷
大多的程序员都会面对定期查找和修改缺陷。过去,这个任务最常用的方法是在代码中散置一些alert调用(this task was most commonly carried out bysprinkling code with alert calls),并刷新浏览器监查变量的值,或者观察哪里出现了期望的流和脚本期望的流的一致(or to observewhere the expected flow of a script diverged from the expected flow)。
如今,大多浏览器都内建一个强大的控制台。那也不容易获得一个像Firebug Lite一样有用的工具。调试过程几乎都是一样的:在代码散置console.log调用,刷新浏览器,观察实际行为,并和预期行为进行人为比较。
调试:一个例子
例如一个调试session的例子,我们来看一个jQuery插件,它期望一个元素具有一个datetime属性(如HTML5时间元素),或一个自定义data-datetime属性,包含一个日期字符串,用人类可读的、和当前时间对比的内容(如3小时之前)替换元素的innerHTML。
[javascript] view plaincopy1. jQuery.fn.differenceInWords = (function () {
2. var units = {
3. second: 1000,
4. minute: 1000 * 60,
5. hour: 1000 * 60 * 60,
6. day: 1000 * 60 * 60 * 24,
7. week: 1000 * 60 * 60 * 24 * 7,
8. month: 1000 * 60 * 60 * 24 * 30
9. };
10.
11. function format(num, type) {
12. return num + " " + type + (num > 1 ? "s" : "");
13. }
14.
15. return function () {
16. this.each(function () {
17. var datetime = this.getAttribute("datetime") ||
18. this.getAttribute("data-datetime");
19. var diff = new Date(datetime) - new Date();
20.
21. if (diff > units.month) {
22. this.innerHTML = "more than a month ago";
23. } else if (diff > units.week) {
24. this.innerHTML = format(Math.floor(diff / units.week), "week") + " ago";
25. } else {
26. var pieces = [], num, consider = ["day", "hour", "minute", "second"], measure;
27.
28. for (var i = 0, l = consider.length; i < l; ++i) {
29. measure = units[consider[i]];
30.
31. if (diff > measure) {
32. num = Math.floor(diff / measure);
33. pieces.push(format(num, consider[i]));
34. }
35. }
36.
37. this.innerHTML = (pieces.length == 1 ? pieces[0] :
38. pieces.slice(0, pieces.length - 1).join(", ") + " and " +
39. pieces[pieces.length - 1]) + " ago";
40. }
41. });
42. };
43. }());
该代码首先处理两种特殊的情况:差值大于一个月表示成“超过一个月(more than a month)”,差值大于一个星期时显示星期数。函数然后差值收集准确的天数、小时数和秒数。当差值小于一天时,忽略天数,依此类推。
代码看上去很合理,但是使用它时,马上就会发布有些不太对劲。"Humanizing"一个8天的日期,返回“"and undefined”。使用console.log调试策略,我们应该开始并记录初始的中间值来判定什么错了。如记录初始差值提醒我们实际得到的顺序是错误的。好了,我们修正它:
[javascript] view plaincopy1. var diff = new Date(datetime.replace(/\+.*/, "")) - new Date();
得到正确差值解决了问题,我们现在得到了我们期望的“"1 week ago”。然后我们把这个插件放到产品中并期望它作为产品的一部分也能工作的很好(So we toss theplugin into production and keep happily hacking on some other part of theapplication.)。
第二天,有人温和的通知我们那个“三天,80小时,4854分钟和291277秒”("3 days, 80 hours, 4854minutes and 291277 seconds" )是不可接受的时间戳格式。结果我们在测试日期小于一周时失败了。键入console.log,我们乱丢包括记录语句的代码(可能可能引入一些我们刚刚清除的记录语句)最后发现剩下的差值不应该每次都重新计算: