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 –


