模拟/存根构造

问题描述:

我有以下代码:模拟/存根构造

class Clients 
    constructor : -> 
    @clients = [] 

    createClient : (name)-> 

    client = new Client name 
    @clients.push client 

我与茉莉花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,它有一种方法来创建间谍/模拟/存根,但它似乎不可能测试构造函数。所以我正在寻找一种方法来测试构造函数,如果有一种方法我不需要额外的库,但是我对任何东西都是开放的,那么它将会很好。

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

我掀起了一些示例代码,但我没有用茉莉花测试它。希望你能得到它是如何工作的要点:

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对象。然后这个工厂在测试中被模拟,让你可以准确地控制返回的内容,并检查它是否被正确调用。

+0

我很害怕我必须这样解决它。尽管如此,很好的答案,谢谢。 – Pickels

可能在茉莉存根出的构造,语法只是有点出乎意料:

spy = spyOn(window, 'Clients'); 

换句话说,你不踩灭了new方法,你踩灭类在它所处的环境中命名本身,在这种情况下为window。然后,您可以链接andReturn()以返回您选择的虚假对象,或者使用andCallThrough()来调用真正的构造函数。

参见:Spying on a constructor using Jasmine

+1

如果Clients是闭包上的变量,则这不起作用。 – Zequez

我的解决办法结束了类似@zpatokal

最后我用一个模块翻过我的应用程序(不是真正的大的应用程序),并从那里嘲笑。一个问题是,and.callThrough将无法​​正常工作,因为构造函数将从Jasmine方法中调用,所以我不得不用and.callFake做一些诡计。

在unit.coffee

class PS.Unit 

在units.coffee

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

而且在规范文件:

Unit = PS.Unit 

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

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

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