2012-07-12 192 views
21

我想測試一個控制器,這取決於我自己建立的服務。我想嘲笑這項服務,因爲服務與DOM對話。注入一個angularjs控制器測試的模擬服務

這是我目前的測試:

describe('Player Controllers', function() { 

    beforeEach(function() { 
     this.addMatchers({ 
      toEqualData: function (expected) { 
       return angular.equals(this.actual, expected); 
      } 
     }); 
    }); 

    describe('TestPSPlayerModule', function() { 
     var $httpBackend, scope, ctrl; 

     beforeEach(module('PSPlayerModule')); 

     beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { 
      $httpBackend = _$httpBackend_; 

      scope = $rootScope.$new(); 
      ctrl = $controller(PlayerController, { $scope: scope }); 
     })); 

     it('should request a clip url from the server when clipClicked is called', function() { 
      expect(1).toBe(1); 
     }); 
    }); 

}); 

我的控制器看起來是這樣的:

w.PlayerController = function ($scope, $http, $window, speedSlider, $location) { 
    ... 
} 

所以這是我想嘲笑speedSlider。

我有主意,用一個模塊我在測試代碼創建了一個可以提供僞造的實施速度滑塊,所以我增加了以下的test.js文件的頂部:

module('TestPSPlayerModule', []).factory('speedSlider', function() { 
    return = { 
     ... 
    }; 
}); 

,然後列出在beforeEach該模塊()調用,而不是具體的一個,但如果我這樣做,我得到以下錯誤:

Injector already created, can not register a module! 

所以我想一定有給我提供了一個更好的辦法模擬執行我的一項服務。我可以使用sinon.js作爲...

+0

你見過這個文檔嗎? http://docs.angularjs.org/guide/dev_guide.services.testing_services其中'$ window'被嘲笑。這是一個相當簡單的例子,但它可能爲您想要做的事提供模板。 – 2012-07-12 22:31:05

+0

@NoahFreitas你提供的鏈接現在已經死亡 – Stephane 2015-04-11 14:35:53

+1

@StephaneEybert,看起來它已被移動並更新到這裏:https://docs.angularjs.org/guide/services#unit-testing – 2015-04-11 18:01:14

回答

6

確保在您使用模塊後,您沒有額外的括號。所以module('TestPSPlayer')而不是module('TestPSPlayer',[])

40

還要確保你不試圖做到這一點的注入函數調用內:

這將引發錯誤:

beforeEach(inject(function(someOtherService) { 
     module('theApp', function($provide) { 
      myMock = {foo: 'bar'}; 
      $provide.value('myService', myServiceMock); 
      someOtherService.doSomething(); 
     }); 
    })); 

這不會:

beforeEach(function() { 
     module('theApp', function($provide) { 
      myMock = {foo: 'bar'}; 
      $provide.value('myService', myServiceMock); 
     }); 

     inject(function(someOtherService) { 
      someOtherService.doSomething(); 
     }); 
    }); 
+0

更多相關imho – davidjnelson 2014-10-11 02:01:25

+7

嵌套'module( )'inject()'裏面'不是導致錯誤的原因。實際上,所有的'module()'調用都必須是_before_'inject()'。 – 2014-11-18 10:15:49

+0

@HermanKan爲什麼? – tobi 2015-04-14 05:38:25

4

在我的情況這沒有奏效:

beforeEach(module('user')); 
beforeEach(inject(function ($http) { 
})); 

beforeEach(module('community')); 
beforeEach(inject(function ($controller, $rootScope) { 
})); 

我已經改變了這使它的工作:

beforeEach(module('user')); 
beforeEach(module('community')); 

beforeEach(inject(function ($http) { 
})); 
beforeEach(inject(function ($controller, $rootScope) { 
})); 
+0

這解釋了應該在所有模塊初始化之後調用注入 – 2016-05-31 10:56:20

0

如果您的提供商不使用全局初始化,您可以使用原來的注射提供商和嘲笑它。在下面的示例中,是您的控制器。

var injectedProviderMock; 

beforeEach(function() { 
    module('myModule'); 
}); 

beforeEach(inject(function (_injected_) { 
    injectedProviderMock = mock(_injected_); 
})); 


var testedProvider; 
beforeEach(inject(function (_testedProvider_) { 
    testedProvider = _testedProvider_; 
})); 

it("return value from injected provider", function() { 
    injectedProviderMock.myFunc.andReturn('testvalue'); 
    var res = testedProvider.executeMyFuncFromInjected(); 
    expect(res).toBe('testvalue'); 
}); 

//mock all provider's methods 
function mock(angularProviderToMock) { 

    for (var i = 0; i < Object.getOwnPropertyNames(angularProviderToMock).length; i++) { 
     spyOn(angularProviderToMock,Object.getOwnPropertyNames(angularProviderToMock)[i]); 
    } 
    return angularProviderToMock; 
}