Javascript 测试框架 Jasmine(六):异步代码测试
2014-06-21 · 652 chars · 4 min read
模拟 Timeout#
Jasmine Clock 可以用来测试setTimeout 和setInterval 的回调操作。它使回调函数同步执行,当 Clock 的时间超过 timer 的时间,回调函数会被触发一次。这使依赖于时间的代码更加易于测试。
Jasmine Clock 使用jasmine.clock().install 在需要调用 timer 函数的 spec 和 suite 中初始化。在执行完测试的时候,一定要卸载 Clock 来还原 timer 函数。使用jasmine.clock().tick 设置时间以使注册的回调触发。
describe('Jasmine Clock 测试', function () {
var timerCallback
beforeEach(function () {
timerCallback = jasmine.createSpy('timerCallback')
jasmine.clock().install()
})
afterEach(function () {
jasmine.clock().uninstall()
})
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.calls.count()).toEqual(1)
jasmine.clock().tick(50)
expect(timerCallback.calls.count()).toEqual(1)
jasmine.clock().tick(50)
expect(timerCallback.calls.count()).toEqual(2)
})
})
异步支持#
Jasmine 支持测试需要执行异步操作的 specs,调用beforeEach , it , 和afterEach 的时候,可以带一个可选的参数done ,当 spec 执行完成之后需要调用done 来告诉 Jasmine 异步操作已经完成。默认 Jasmine 的超时时间是 5s,可以通过全局的jasmine.DEFAULT_TIMEOUT_INTERVAL 设置。
describe('Jasmine 异步测试演示', function () {
var value
beforeEach(function (done) {
setTimeout(function () {
value = 0
done()
}, 1)
})
it('should support async execution of test preparation and expectations', function (done) {
value++
expect(value).toBeGreaterThan(0)
done()
})
describe('5秒钟', function () {
var originalTimeout
beforeEach(function () {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL
jasmine.DEFAULT_TIMEOUT_INTERVAL = 6000
})
it('takes a long time', function (done) {
setTimeout(function () {
done()
}, 5000)
})
afterEach(function () {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout
})
})
})
在线测试,注意要等 5s 才有结果。
测试 ajax 回调#
jasmine-ajax 插件(https://github.com/pivotal/jasmine-ajax)用来模拟测试 ajax。注意这是个单独的文件,需要额外引用。目前感觉这个用处不大(不然不会以插件的形式出现,呵呵),具体就不说了,这是官方文档:http://jasmine.github.io/2.0/ajax.html,下面直接看个例子:
describe("mocking ajax", function() {
describe("suite wide usage", function() {
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it("specifying response when you need it", function() {
var doneFn = jasmine.createSpy("success");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(arguments) {
if (this.readyState == this.DONE) {
doneFn(this.responseText);
}
};
xhr.open("GET", "/some/cool/url");
xhr.send();
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');
expect(doneFn).not.toHaveBeenCalled();
jasmine.Ajax.requests.mostRecent().response({
"status": 200,
"contentType": 'text/plain',
"responseText": 'awesome response'
});
expect(doneFn).toHaveBeenCalledWith('awesome response');
});
it("allows responses to be setup ahead of time", function() {
var doneFn = jasmine.createSpy("success");
jasmine.Ajax.stubRequest('/another/url').andReturn({
"responseText": 'immediate response'
});
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(arguments) {
if (this.readyState == this.DONE) {
doneFn(this.responseText);
}
};
xhr.open("GET", "/another/url");
xhr.send();
expect(doneFn).toHaveBeenCalledWith('immediate response')
});
});
it("allows use in a single spec", function() {
var doneFn = jasmine.createSpy('success');
jasmine.Ajax.withMock(function() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(arguments) {
if (this.readyState == this.DONE) {
doneFn(this.responseText);
}
};
xhr.open("GET", "/some/cool/url");
xhr.send();
expect(doneFn).not.toHaveBeenCalled();
jasmine.Ajax.requests.mostRecent().response({
"status": 200,
"responseText": 'in spec response'
});
expect(doneFn).toHaveBeenCalledWith('in spec response');
});
});
});


