toThrow 检验一个函数是否会抛出一个错误
it("toThrow检验一个函数是否会抛出一个错误", function() {
var foo = function() {
return 1 + 2;
};
var bar = function() {
return a + 1;
};
expect(foo).not.toThrow();
expect(bar).toThrow();
}); |
注:describe可嵌套
xdescribe 和 xit:路过不执行,结果不显示。像display:none。点控制栏中skipped显示
Spy 存储函数的被调用情况和参数(函数监视器,记录被调用情况,但函数并不真执行)
describe("对spy函数的测试", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar'); //foo为spy函数
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("测试foo函数是否被调用过",
function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("测试foo函数被调用的次数",
function() {
expect(foo.setBar.calls.length).toEqual(2);
});
it("测试foo函数被调用时传入的参数",
function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456,
'another param');
});
it("上一次被调用的参数", function()
{
expect(foo.setBar.mostRecentCall.args[0]).toEqual(456);
});
it("所有被调用的情况存在一个数组里",
function() {
expect(foo.setBar.calls[0].args[0]).toEqual(123);
});
it("函数并未真的执行", function()
{
expect(bar).toBeNull();
});
}); |
Spy addCallThrough 函数监视器,但函数真的执行
describe("对spy函数的测试,函数真的执行", function() {
var foo, bar, fetchedBar;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
},
getBar: function() {
return bar;
}
};
//spyOn(foo, "setBar"); //如果加上这句,setBar不真的执行,后两个spec不通过
spyOn(foo, 'getBar').andCallThrough();
foo.setBar(123);
fetchedBar = foo.getBar();
});
it("测试foo中getBar函数是否被调用过", function() {
expect(foo.getBar).toHaveBeenCalled();
});
it("foo中setBar函数真的执行了", function() {
expect(bar).toEqual(123);
});
it("foo中getBar函数真的执行了", function() {
expect(fetchedBar).toEqual(123);
});
}); |
Spy andReturn 函数监视器,函数不真的执行。指定监视的函数的返回值
describe("A spy, when faking a return value", function() {
var foo, bar, fetchedBar;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
},
getBar: function() {
return bar;
}
};
spyOn(foo, 'getBar').andReturn(745);
//指定getBar函数返回745
foo.setBar(123);
fetchedBar = foo.getBar();
});
it("测试foo中getBar函数是否被调用过",
function() {
expect(foo.getBar).toHaveBeenCalled();
});
it("不影响未被监视的其它函数",
function() {
expect(bar).toEqual(123);
});
it("指定的返回值745", function()
{
expect(fetchedBar).toEqual(745);
});
}); |
Spy addCallFake 替代被监视的函数,原函数不执行
describe("替代被监视的函数,原函数不执行", function() {
var foo, bar, fetchedBar;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
},
getBar: function() {
alert("frostbelt");
return bar;
}
};
spyOn(foo, 'getBar').andCallFake(function()
{
return 1001;
});
foo.setBar(123);
fetchedBar = foo.getBar();
});
it("测试foo中getBar函数是否被调用过",
function() {
expect(foo.getBar).toHaveBeenCalled();
});
it("不影响未被监视的其它函数",
function() {
expect(bar).toEqual(123);
});
it("getBar被addCallFake指定的匿名函数代替,getBar不执行",
function() {
expect(fetchedBar).toEqual(1001);
});
}); |
如果你没有什么可监视的又实在想监视一下,该咋办?自己create一个被监视函数。。
jasmine.createSpy(functionId)
describe("自己造一个被监视函数。啊,我凌乱了。。", function() {
var whatAmI;
beforeEach(function() {
whatAmI = jasmine.createSpy('whatAmI');
whatAmI("I", "am",
"a", "spy");
});
it("有个id,是createSpy的传入函数,用于报错",
function() {
expect(whatAmI.identity).toEqual('whatAmI')
});
it("是否被调用", function()
{
expect(whatAmI).toHaveBeenCalled();
});
it("被调用的次数", function()
{
expect(whatAmI.calls.length).toEqual(1);
});
it("被调用的参数", function()
{
expect(whatAmI).toHaveBeenCalledWith("I",
"am", "a", "spy");
});
it("最近一次被调用", function()
{
expect(whatAmI.mostRecentCall.args[0]).toEqual("I");
});
}); |
有时需要监视一个对象的很多方法,用createSpyObj添加方法数组
jasmine.createSpyObj(obj, methodArray)
describe("有时需要监视一个对象的很多个方法,用createSpyObj添加数组", function() {
var tape;
beforeEach(function() {
tape = jasmine.createSpyObj('tape',
['play', 'pause', 'stop', 'rewind']);
tape.play();
tape.pause();
tape.rewind(0);
});
it("tape对象的这四个方法已被定义",
function() {
expect(tape.play).toBeDefined();
expect(tape.pause).toBeDefined();
expect(tape.stop).toBeDefined();
expect(tape.rewind).toBeDefined();
});
it("四个方法是否被调用", function()
{
expect(tape.play).toHaveBeenCalled();
expect(tape.pause).toHaveBeenCalled();
expect(tape.rewind).toHaveBeenCalled();
expect(tape.stop).not.toHaveBeenCalled();
});
it("被调用时传入的参数", function()
{
expect(tape.rewind).toHaveBeenCalledWith(0);
});
}); |
jasmine.any 类型判断。instanceof
describe("类型匹配", function() {
it("相当于instanceof",
function() {
expect({}).toEqual(jasmine.any(Object));
expect(12).toEqual(jasmine.any(Number));
});
it("也可以用于spy", function()
{
var foo = jasmine.createSpy('foo');
foo(12, function() {
return true
});
expect(foo).toHaveBeenCalledWith(jasmine.any(Number),
jasmine.any(Function));
//foo被调用时的参数 类型判断
});
}); |
jasmine.Clock.useMock() jasmine自己控制时间,实现异步调试,减少等待
jasmine.Clock.tick(n:uint) 向前n毫秒
describe("jasmine自己控制时间,实现异步调试,减少等待", function() {
var timerCallback;
beforeEach(function() {
timerCallback = jasmine.createSpy('timerCallback');
jasmine.Clock.useMock();
});
it("setTimeout", function()
{
setTimeout(function() {
timerCallback();
}, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.Clock.tick(101);
expect(timerCallback).toHaveBeenCalled();
});
it("setInterval", function()
{
setInterval(function() {
timerCallback();
}, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.Clock.tick(101);
expect(timerCallback.callCount).toEqual(1);
jasmine.Clock.tick(50);
expect(timerCallback.callCount).toEqual(1);
jasmine.Clock.tick(50);
expect(timerCallback.callCount).toEqual(2);
});
}); |
注:在这种环境下setTimeout和setInterval的callback为同步的,系统时间不再影响执行
runs(function) waitsFor(function, message,
millisec) Jasmine异步调试 按自己的理解写个例子
describe("jasmine异步调试,对ajax结果的断言", function(){
var data, flag = false;
it("ajax是否按时返回了正确结果",
function(){
runs(function(){
$.post(
url,
{},
function(data){
flag = true;
data = data.someAttr;
}
);
});
waitsFor(function(){ //flag为true或到2秒时执行
2秒内返回true则执行最后一个runs,到时未返回则本spec出错,返回第二个参数错误信息
return flag;
}, "ajax在指定时间2秒内未返回",
2000);
runs(function(){ //直到waitsFor返回true时执行
expect(data).toEqual("someThing");
})
});
}); |
注:it是一个spec,包含
runs(function)
waitsFor(function, message, millsec)
runs(function)
|
第一个runs里有一些异步的代码
waitsFor中的funciton如果在millsec内返回true,执行最后一个runs
如果在millsec内不能返回true,spec不通过,显示错误信息message
e) 使用
在测试的页面里加入以下代码:
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var trivialReporter = new jasmine.TrivialReporter();
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.specFilter = function(spec)
{
return trivialReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script> |
导入jasmine.css jasmine.js jasmine-html.js
src.js(源代码) test.js(存放describes)
JsTestDriver
a) 简介
JsTestDriver是一个JavaScript单元测试工具,易于与持续构建系统相集成并能够在多个浏览器上运行测试轻松实现TDD风格的开发。当在项目中配置好JsTestDriver以后,如同junit测试java文件一般,JsTestDriver可以直接通过运行js文件来进行单元测试。JsTestDriver框架本身就是JAVA的jar包,需要在本地运行并监听一个端口。
b) 优点
可以一次测试多个浏览器,使用方法是在启动服务时可以将多个浏览器的路径作为参数传进去。可以在多台机器上的浏览器中运行,包括移动设备。
测试运行得很快,因为不需要将结果添加到DOM中呈现出来,它们能够同时在任意多的浏览器中运行,未修改的文件浏览器会从缓存提取。
不需要HTML配件文件,仅仅只需提供一个或多个脚本和测试脚本,测试运行器运行时会创建一个空文件。
能很方便的和Ant、Maven等进行集成进行自动化测试,也可以方便和Jekins等持续集成工具进行集成,可以生成测试结果的XML文档。
有Eclipse和IntelliJ插件,可以很方便的在这两个IDE中进行测试,和JUnit很像。
支持其它测试框架,可以测试其它测试框架写的测试代码,比如有对应的插件可以将QUnit和Jasmine测试代码转换成JsTestDriver的测试代码。
c) 不足
不能在浏览器中测试,只能通过自动化工具或控制台运行。生成的结果不够直观。
安装使用稍微有点麻烦,依赖于JAVA环境。
d) API
assert(msg, value)
assertTrue(msg, value)
assertFalse(msg, value)
assertEquals(msg, expected, actual)
assertNotEquals(msg, expected, actual)
assertSame(msg, expected, actual)
assertNotSame(msg, expected, actual)
assertNull(msg, value)
assertNotNull(msg, value)
assertUndefined(msg, value)
assertNotUndefined(msg, value)
assertNaN(msg, number)
assertNotNaN(msg, number)
assertException(msg, callback, type)
assertNoException(msg, callback)
assertArray(msg, arrayLike)
assertTypeOf(msg, type, object)
assertBoolean(msg, value)
assertFunction(msg, value)
assertNumber(msg, value)
assertObject(msg, value)
assertString(msg, value)
assertMatch(msg, pattern, string)
assertNoMatch(msg, pattern, string)
assertTagName(msg, tagName, element)
assertClassName(msg, className, element)
assertElementId(msg, id, element)
assertInstanceOf(msg, constructor, object)
assertNotInstanceOf(msg, constructor, object)
|
API按字面意思理解即可,不一一标注
e) 使用
前提:
安装java环境
下载JsTestDriver.jar
目录:
JsTestDriver.jar
jsTestDriver.conf //配置文件,默认名称,如果用其它名称,需要指定config参数
src
----src.js
test
----test.js
jsTestDriver.conf:
src.js:
test.js:
像java的JUnit一样,测试方法名要以”test”开头,如:”testXXXX”
测试步骤:
1.cmd 进入目录
2.运行命令”java –jar JsTestDriver.jar –port
9876”
3.打开页面http://localhost:9876,点击“捕获浏览器”。
4.新打开一个终端,运行命令”java –jar JsTestDriver.jar
–tests all”,运行所有测试用例
5.也可以单独运行某一个用例,如运行命令” java –jar JsTestDriver.jar
–tests addTest.testA”
FireUnit
a) 简介
FireUnit是一个基于Firebug的Javascript的单元测试框架。简单说来,FireUnit给Firebug增加了一个标签面板,并提供了一些简单的JavaScript
API来记录和查看测试。
b) 优点
简单易用
c) 不足
功能不多,测试代码常常写在源码里,虽然可以实时地看到效果,但耦合太强,不易清理
只运行在Firefox下
d) API
常用:
fireunit.ok(condition, message) true/false
fireunit.compare(actual, expect, message) 是否相等
fireunit.reCompare(regexp, string, message) 字符串是否与正则式匹配
fireunit.testDone(); 执行以上的测试,在Firebug的新标签test中显示结果
其它:
fireunit.runTests(“test2.html”, “test3.html”) 一起运行多个页面的测试(每个文件都含有一些独立的测试)
fireunit.log(message) 打印log,但似乎不管用
fireunit.id(id) 相当与document.getElementById
fireunit.click(element) 模拟触发element的click事件
fireunit.focus(element) 模拟触发element的focus事件
fireunit.mouseDown(element) 模拟触发element的mouseDown事件
但看代码明明是click事件
在FF下,只是执行了node.click();不会触发onmousedown,只会触发onclick。已验证
fireunit.value(element) 修改element的value
fireunit.key(element, key) 模拟触发element的key事件
例:
var input = document.getElementsByTagName(“input”)[0];
fireunit.key(input, “a”);
|
没用过:
fireunit.browser
fireunit.test
fireunit.forceHTTP
fireunit.registerPathHandler
fireunit.panel
fireunit.privilege
|
e) 使用
在FF下装Firebug和FireUnit
直接在代码里写测试,就像console.log();
4. 小结
QUnit框架简单方便,测试界面直观详细,Jasmine功能强大,风格也简单明了,符合前端开发者的编程习惯,推荐JsTestDriver可以和QUnit等框架结合,可以同时测多个浏览器。但安装复杂,只能在控制台显示,不友好,不够清晰。FireUnit小巧灵活,加上Firebug的人气应该很受欢迎。如果需要进行自动化测试,
多了解一下Jasmine和JsTestDriver,本文未深入。
|