错误处理与测试
一、错误处理
一)try-catch语句
function atest() { try { //可能发生错误的代码 return 0; } catch (error) { //错误处理程序 console.log(error.message); return 1; } finally { //无论如何都会执行的,函数最后返回2 return 2; } }
错误类型:
1)Error:错误基类,其他错误类型都由该类继承。
2)EvalError:没有把eval()当函数调用时,会发送该错误。
3)RangeError:数值超出范围
4)ReferenceError:找不到对象时
5)SyntaxError:传入eval()函数的语法错误时
6)TypeError:变量的类型不符合要求
合理使用try-catch:
使用 try-catch 最适合处理那些我们无法控制的错误。假设你在使用一个大型 JavaScript 库中的
函数,该函数可能会有意无意地抛出一些错误。由于我们不能修改这个库的源代码,所以大可将对该函
数的调用放在 try-catch 语句当中,万一有什么错误发生,也好恰当地处理它们。
在明明白白地知道自己的代码会发生错误时,再使用 try-catch 语句就不太合适了。例如,如果
传递给函数的参数是字符串而非数值,就会造成函数出错,那么就应该先检查参数的类型,然后再决定
如何去做。在这种情况下,不应用使用 try-catch 语句。
二)抛出错误
使用throw操作符可以抛出错误,对抛出的值没有要求
//有效 throw 111; throw ''ss;
在遇到 throw 操作符时,代码会立即停止执行。仅当有 try-catch 语句捕获到被抛出的值时,代
码才会继续执行。
通过使用某种内置错误类型,可以更真实地模拟浏览器错误。每种错误类型的构造函数接收一个参
数,即实际的错误消息。
throw new Error("An error");
何时抛出与捕获:
只应该捕获那些你确切地知道该如何处理的错误。捕获错误的
目的在于避免浏览器以默认方式处理它们;而抛出错误的目的在于提供错误发生具体原因的消息。
三)错误事件
任何没有通过 try-catch 处理的错误都会触发 window 对象的 error 事件 ,在任何 Web 浏览器中, onerror 事件处理程序都不会创建 event 对象,
但它可以接收三个参数:错误消息、错误所在的 URL 和行号 。要指定 onerror 事件处理程序,必须使用如下所示的 DOM0 级技术,它没有遵循“DOM2 级
事件”的标准格式。
window.onerror = function(msg, url, line) { log(msg);
//阻止浏览器报告错误的行为
return fales;
}
二、测试
一)日志记录
//一个适用于所有浏览器的log function log() { try { console.log.apply(console, arguments); } catch(e) { try { opera.postError.apply(opera, arguments); } catch (e) { alert(Array.prototype.join.call(arguments, " ")); } } }
二)测试用例
一个好的测试用例的三个特征:
1)可重用性:多次运行应该产生相同的结果
2)简单性:只专注与测试,消除多余代码的影响
3)独立性:避免一个测试结果依赖于另一个结果
三)测试套件
测试套件的主要目的是聚合代码种的所有单个测试,将其组合成一个单位,这样他们可以批量运行,提供一个可以轻松反复运行的单一资源。
1)断言:
自己实现一个断言:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <style> #results li.pass { color: green; } #results li.fail { color: red; } </style> <body> <ul id="results"></ul> </body> </html> <script> function assert(value, desc) { var liElement = document.createElement("li"); liElement.className = value ? "pass" : "fail"; liElement.appendChild(document.createTextNode(desc)); document.getElementById("results").appendChild(liElement); } window.onload = function () { assert(true, "Success"); assert(false, "Fail"); } </script>
2)测试分组的实现:
(function () { var results; this.assert = function assert(value, desc) { var li = document.createElement("li"); li.className = value ? "pass" : "fail"; li.appendChild(document.createTextNode(desc)); results.appendChild(li); if (!value) { li.parentNode.parentNode.className = "fail"; } return li; } this.test = function test(name, fn) { results = document.getElementById("results"); results = assert(true, name). appendChild(document.createElement("ul")); fn(); } })(); window.onload = function (ev) { test("all true", function () { assert(true, "111"); assert(true, "222"); assert(true, "333"); }); test("one false", function () { assert(false, "failed"); assert(true, "success"); assert(true, "xxx"); }); }
3)异步测试
(function () { var queue = [], paused = false, results; this.assert = function assert(value, desc) { var li = document.createElement("li"); li.className = value ? "pass" : "fail"; li.appendChild(document.createTextNode(desc)); results.appendChild(li); if (!value) { li.parentNode.parentNode.className = "fail"; } return li; }; this.test = function test(name, fn) { queue.push(function () { results = document.getElementById("results"); results = assert(true, name). appendChild(document.createElement("ul")); fn(); }); runTest(); }; function runTest() { if (!paused && queue.length) { queue.shift()(); if (!paused) { resume(); } } } this.pause = function () { paused = true; }; this.resume = function resume() { paused = false; setTimeout(runTest, 1); } })(); window.onload = function (ev) { test("First async test", function () { pause(); setTimeout(function () { assert(true, "First async completed!"); resume(); }, 1000); }); test("Second async test", function () { pause(); setTimeout(function () { assert(true, "Second async test completed!"); resume(); }, 1000); }); }