2014-03-18 190 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() '。 –