The scenario is very simple, I am trying to test a service A, which depends on service B, so I decided to mock service B by overriding it before I inject service A. However, I am also testing service B which is no longer valid since it is overridden. Any idea on how to avoid this?
Application code.
angular.module('MyApp.services')
.factory('serviceB', function(){
return {
greeting: function(){ return 'hello'; }
}
})
.factory('serviceA', ['serviceB', function(serviceB){
return {
greeting: function(){
return 'I say: ' + serviceB.greeting();
}
});
Unit Test:
describe('My app services', function(){
beforeEach(module('MyApp.services'));
describe('service A', function(){
// mock service B
angular.module('MyApp.services').factory('serviceB', function(){
return { greeting: function(){ return 'mocked B'; } }
});
var serviceA;
inject(function(_serviceA_){
serviceA = _serviceA_;
});
it('should work', function(){
var words = serviceA.greeting();
expect(words).toBe('I say: mocked B');
});
});
describe('service B'. function(){
var serviceB;
inject(function(_serviceB_){
serviceB = _serviceB_;
});
it('should work', function(){
var words = serviceB.greeting();
expect(words).toBe('hello');
});
});
});
Your service injection should probably be either in a beforeEach
or as part of the tests, otherwise I think they will happen before the tests begin or not at all, e.g.
beforeEach(inject(function(_serviceA_){
serviceA = _serviceA_;
}));
or
it('should work', inject(function(serviceA){
var words = serviceA.greeting();
expect(words).toBe('I say: mocked B');
}));
To solve the problem you are actually asking about, I suggest you do one of two things:
Override the service in the injector rather than the module
beforeEach(module(function($provide){
$provide.value('serviceB', {
greeting: function(){ return 'mocked B'; }
});
}));
See plunker.
Use a separate module that can be added when needed to override serviceB
Somewhere (that only needs to be called once), put the definition of your new module containing your mock version of serviceB
angular.module('MyApp.services.mock', [])
.factory('serviceB', function(){
return { greeting: function(){ return 'mocked B'; } }
});
then where you currently alter the service in your module under test, use the following to load your module with the mock on top.
beforeEach(module('MyApp.services.mock'));
See plunker
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With