2014-03-18 87 views
7

我在Angular中有一个装饰器,它将扩展$ log服务的功能,我想测试它,但我没有看到这样做的方法。这里是我的装饰的存根:如何测试角装饰器功能

angular.module('myApp') 
    .config(function ($provide) { 

    $provide.decorator('$log', ['$delegate', function($delegate) { 
     var _debug = $delegate.debug; 
     $delegate.debug = function() { 
     var args = [].slice.call(arguments); 

     // Do some custom stuff 

     window.console.info('inside delegated method!'); 
     _debug.apply(null, args); 
     }; 
     return $delegate 
    }]); 

    }); 

注意,这基本上覆盖$log.debug()方法,然后做一些定制的东西后调用它。在我的应用程序这个作品,我看到在控制台中的'inside delegated method!'消息。但在我的测试中,我没有得到那个输出。

我该如何测试我的装饰器功能?
具体来说,我如何注入我的装饰器,使其实际装饰我的$log模拟实现(请参见下文)?

这是我目前的测试(摩卡/柴,但那不是真正相关的):

describe('Log Decorator', function() { 
    var MockNativeLog; 
    beforeEach(function() { 
    MockNativeLog = { 
     debug: chai.spy(function() { window.console.log("\nmock debug call\n"); }) 
    }; 
    }); 

    beforeEach(angular.mock.module('myApp')); 

    beforeEach(function() { 
    angular.mock.module(function ($provide) { 
     $provide.value('$log', MockNativeLog); 
    }); 
    }); 

    describe('The logger', function() { 
    it('should go through the delegate', inject(function($log) { 
     // this calls my mock (above), but NOT the $log decorator 
     // how do I get the decorator to delegate the $log module?? 
     $log.debug(); 
     MockNativeLog.debug.should.have.been.called(1); 
    })); 
    }); 
}); 
+0

但是这个想法(如果我没有弄错的话)是你装饰你的'$ log',然后用模拟器覆盖整个'$ log'。所以很明显,在你的测试中,你将拥有一个具有简单调试功能的函数。我想我错过了一些东西。 –

+0

我为你创建了一个plunker,我不得不针对角度模拟进行一些修改,但请查看:http://plnkr.co/edit/kim2NTNBp0eflOhFVhF3?p =预览 –

+0

也开始制作一个plunker。请注意,对'angular.module()'的调用需要_two_参数... –

回答

6

从连接普拉克(http://j.mp/1p8AcLT),最初的版本所提供的(大部分)代码不变@jakerella(语法的小调整)。我试图使用我可以从原始文章派生出来的相同依赖项。注tests.js:12-14

angular.mock.module(function ($provide) { 
    $provide.value('$log', MockNativeLog); 
}); 

这完全覆盖本机$log服务,如你所料,与测试because angular.mock.module(fn) acts as a config function for the mock module的开头提供的MockNativeLog实施。由于配置功能按先进先出顺序执行,此功能会对装饰的$log服务进行破坏。

一种解决方案是重新申请的装饰里面这个配置的功能,你可以从普拉克第2版看到(永久链接将是很好,Plunker),tests.js:12-18

angular.mock.module('myApp', function ($injector, $provide) { 
    // This replaces the native $log service with MockNativeLog... 
    $provide.value('$log', MockNativeLog); 
    // This decorates MockNativeLog, which _replaces_ MockNativeLog.debug... 
    $provide.decorator('$log', logDecorator); 
}); 

这不是但是,足够了。该装饰@jakerella定义取代$log服务的debug方法,造成MockNativeLog.debug.should.be.called(1)以后调用失败。方法MockNativeLog.debug不再是由chai.spy提供的间谍,所以匹配器将不起作用。

相反,注意,我在tests.js:2-8创建一个额外的间谍:

var MockNativeLog, MockDebug; 

beforeEach(function() { 
    MockNativeLog = { 
     debug: MockDebug = chai.spy(function() { 
      window.console.log("\nmock debug call\n"); 
     }) 
    }; 
}); 

该代码可能是更容易阅读:

MockDebug = chai.spy(function() { 
    window.console.log("\nmock debug call\n"); 
}); 

MockNativeLog = { 
    debug: MockDebug 
}; 

这仍然并不代表良好的检测结果,只是一个健全的检查。在几个小时之后,你的头撞到“为什么不做这项工作”的问题后,这是一种解脱。

请注意,我另外将装饰器函数重构为全局范围,以便我可以在不需要重新定义它的情况下在tests.js中使用它。更好的做法是用$provider.value()重构一个合适的服务,但是这个任务已经留给学生练习......或者比我自己更懒惰的人。 :D

+0

我明白了这将如何工作......但是,拥有全局装饰器功能并不理想。 :)我会努力解压缩到一个服务。 – jakerella

+0

那么,我可以得到这个全球对象,但不是服务。哎呀。我不断收到'错误:[$ injector:unpr]未知提供者:LogDecorator'。无论如何,感谢您的其他帮助,我会看到我能做些什么,它是另一次服务。 – jakerella

+0

@jakerella因为这是在配置函数中使用的,所以现在可能不得不使用'$ provider.provider()',现在我想到了它......或者可能只是'$ provider.constant() '。 –