模拟/存根构造函数

时间:2011-09-25 22:09:59

标签: javascript coffeescript jasmine

我有以下代码:

class Clients
  constructor : ->
    @clients = []

  createClient : (name)->

    client = new Client name
    @clients.push client

我正在使用Jasmine BDD测试它:

describe 'Test Constructor', ->

  it 'should create a client with the name foo', ->

    clients = new clients
    clients.createClient 'Foo'
    Client.should_have_been_called_with 'Foo'

  it 'should add Foo to clients', ->

    clients = new clients
    clients.createClient 'Foo'

    expect(clients.clients[0]).toEqual SomeStub

在我的第一个测试中,我想检查是否使用正确的名称调用构造函数。在我的第二个,我只是想确认从新客户端发出的任何内容都被添加到数组中。

我正在使用Jasmine BDD,它有一种创建间谍/模拟/存根的方法,但似乎无法测试构造函数。所以我正在研究一种测试构造函数的方法,如果有一种方法我不需要额外的库,但我对任何东西都是开放的。

4 个答案:

答案 0 :(得分:9)

可能会在Jasmine中删除构造函数,语法有点出乎意料:

spy = spyOn(window, 'Clients');

换句话说,你没有隐藏new方法,你在它所居住的上下文中隐藏了类名本身,在本例中是window。然后,您可以在andReturn()上链接以返回您选择的假对象,或者andCallThrough()来调用真正的构造函数。

另请参阅:Spying on a constructor using Jasmine

答案 1 :(得分:4)

我认为这里最好的计划是将新Client对象的创建推广到单独的方法。这将允许您单独测试Clients类并使用模拟Client对象。

我已经编写了一些示例代码,但我还没有使用Jasmine进行测试。希望你能得到它的工作原理:

class Clients
  constructor: (@clientFactory) ->
    @clients = []

  createClient : (name)->
    @clients.push @clientFactory.create name

clientFactory = (name) -> new Client name

describe 'Test Constructor', ->

  it 'should create a client with the name foo', ->
    mockClientFactory = (name) ->
    clients = new Clients mockClientFactory

    clients.createClient 'Foo'

    mockClientFactory.should_have_been_called_with 'Foo'

  it 'should add Foo to clients', ->
    someStub = {}
    mockClientFactory = (name) -> someStub
    clients = new Clients mockClientFactory

    clients.createClient 'Foo'

    expect(clients.clients[0]).toEqual someStub

基本计划现在使用单独的函数(clientFactory)来创建新的Client对象。然后在测试中模拟该工厂,允许您准确控制返回的内容,并检查它是否已被正确调用。

答案 2 :(得分:0)

我的解决方案最终类似于@zpatokal

我最终在我的应用程序中使用了一个模块(不是真正的大应用程序),并且从那里开始嘲笑。一个问题是and.callThrough不会起作用,因为构造函数将从Jasmine方法调用,所以我不得不用and.callFake做一些诡计。

在unit.coffee上

class PS.Unit

在units.coffee上

class PS.Units
  constructor: ->
    new PS.Unit

在spec文件中:

Unit = PS.Unit

describe 'Units', ->
  it 'should create a Unit', ->
    spyOn(PS, 'Unit').and.callFake -> new Unit arguments... # and.callThrough()
    expect(PS.Unit).toHaveBeenCalled()

答案 3 :(得分:0)

最近的茉莉花版本更清晰的解决方案:

window.Client = jasmine.createSpy 'Client'
clients.createClient 'Foo'
expect(window.Client).toHaveBeenCalledWith 'Foo'