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)