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'); }); }); });