Angular unit-test controllers - mocking service inside controller
There are two ways (or more for sure).
Imagining this kind of service (doesn't matter if it is a factory):
app.service('foo', function() { this.fn = function() { return "Foo"; };});
With this controller:
app.controller('MainCtrl', function($scope, foo) { $scope.bar = foo.fn();});
One way is just creating an object with the methods you will use and spy them:
foo = { fn: function() {}};spyOn(foo, 'fn').andReturn("Foo");
Then you pass that foo
as a dep to the controller. No need to inject the service. That will work.
The other way is to mock the service and inject the mocked one:
beforeEach(module('app', function($provide) { var foo = { fn: function() {} }; spyOn(foo, 'fn').andReturn('Foo'); $provide.value('foo', foo);}));
When you inject then foo
it will inject this one.
See it here: http://plnkr.co/edit/WvUIrtqMDvy1nMtCYAfo?p=preview
Jasmine 2.0:
For those that struggle with making the answer work,
as of Jasmine 2.0 andReturn()
became and.returnValue()
So for example in the 1st test from the plunker above:
describe('controller: MainCtrl', function() { var ctrl, foo, $scope; beforeEach(module('app')); beforeEach(inject(function($rootScope, $controller) { foo = { fn: function() {} }; spyOn(foo, 'fn').and.returnValue("Foo"); // <----------- HERE $scope = $rootScope.$new(); ctrl = $controller('MainCtrl', {$scope: $scope , foo: foo }); })); it('Should call foo fn', function() { expect($scope.bar).toBe('Foo'); });});
(Source: Rvandersteen)