Javascript 测试框架 Jasmine(三):Setup、Teardown、嵌套 describe 等
2014-06-20 · 891 chars · 5 min read
上一篇把 Matcher 说了说,本来该说自定义 Matcher 的,但是发现有些七七八八的细节没讲,那就今天先把这些基础说了。
Setup and Teardown#
Setup 和 Teardown 可以帮助 Suite 执行一些重复的代码,Jasmine 提供了beforeEach
和afterEach
函数。很显然,beforeEach
在 describe 中的任何 spec 执行之前运行,afterEach
在任何 spec 执行之后运行。具体的逻辑看 Demo 就一目了然了:
describe('Setup和Teardown示例', function () { var foo beforeEach(function () { foo = 0 foo += 1 }) afterEach(function () { foo = 0 }) it('测试1', function () { expect(foo).toEqual(1) }) it('测试2', function () { expect(foo).toEqual(1) expect(true).toEqual(true) }) })
前面说过 javascript 的作用域规则在 Jasmine 中是适用的,但是这里可以通过this
在beforeEach
,it
,afterEach
中间共享变量。每个 spec 的this
默认指向空的 object。
describe('this用法示例', function () { beforeEach(function () { this.foo = 0 }) it('使用this共享状态', function () { expect(this.foo).toEqual(0) this.bar = 'test pollution?' }) it('下个Spec执行前this会被重置为空Object', function () { expect(this.foo).toEqual(0) expect(this.bar).toBe(undefined) }) })
嵌套 describe#
可以嵌套使用 describe,形成一个 Suite 树,在一个 spec 执行之前,Jasmine 会顺序执行这颗树上的所有beforeEach
。同样的,执行完 spec 后,也会顺序执行树上的所有afterEach
describe('测试嵌套describe:level1', function () { var foo beforeEach(function () { alert('level1:Setup') }) afterEach(function () { alert('level1:Teardown') }) it('level1:测试', function () { alert('level1:测试') }) describe('测试嵌套describe:level2', function () { beforeEach(function () { alert('level2:Setup') }) afterEach(function () { alert('level2:Teardown') }) it('level2:测试', function () { alert('level2:测试') }) }) })
具体的执行顺序,点击这里查看上例的效果,你就全明白了。
禁用 Suites 和挂起 Specs#
可以使用xdescribe
和xit
函数禁用 Suites 和 specs。当 Suites 被禁用后,将不显示在报表中。
xdescribe('A spec', function () { var foo beforeEach(function () { foo = 0 foo += 1 }) it('is just a function, so it can contain any code', function () { expect(foo).toEqual(1) }) })
另外可以使用pending
函数将 specs 挂起,挂起 specs 和使用xit
函数定义的 spec 一样,spec 不会被执行,但是名字会出现在报表中。另外只有名字,没有实际代码的 spec 也会在结果中显示为挂起的状态。pending
可以在 spec 函数体的任何地方调用,不管函数体内有没有 expectations,还是看个例子:
describe('Pending specs', function () { xit("can be declared 'xit'", function () { expect(true).toBe(false) }) it("can be declared with 'it' but without a function") it("can be declared by calling 'pending' in the spec body", function () { expect(true).toBe(false) pending() }) })
jasmine.any#
jasmine.any
接受构造函数或者“Class”名作为期望值,如果这个构造函数(Class)和实际值的构造函数(Class)匹配,则返回true
。继续看例子:
describe('jasmine.any', function () { it('matches any value', function () { expect({}).toEqual(jasmine.any(Object)) expect(12).toEqual(jasmine.any(Number)) }) describe('when used with a spy', function () { it('is useful for comparing arguments', function () { var foo = jasmine.createSpy('foo') foo(12, function () { return true }) expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function)) }) }) })
jasmine.objectContaining#
当一个你只关心实际值是否包含某个键值对的时候,可以使用jasmine.objectContaining
:
describe('jasmine.objectContaining', function () { var foo beforeEach(function () { foo = { a: 1, b: 2, bar: 'baz', } }) it('matches objects with the expect key/value pairs', function () { expect(foo).toEqual( jasmine.objectContaining({ bar: 'baz', }), ) expect(foo).not.toEqual( jasmine.objectContaining({ c: 37, }), ) }) describe('when used with a spy', function () { it('is useful for comparing arguments', function () { var callback = jasmine.createSpy('callback') callback({ bar: 'baz', }) expect(callback).toHaveBeenCalledWith( jasmine.objectContaining({ bar: 'baz', }), ) expect(callback).not.toHaveBeenCalledWith( jasmine.objectContaining({ c: 37, }), ) }) }) })
– 下一篇讲一下自定义 Matcher –