How do you mock a service in AngularJS while unit testing with jasmine?

Say I have a shop service that depends on two services with stateful schedule and warehouse . How do I insert different versions of schedule and warehose in the shop for unit testing?

Here is my service:

 angular.module('myModule').service('shop', function(schedule, warehouse) { return { canSellSweets : function(numRequiredSweets){ return schedule.isShopOpen() && (warehouse.numAvailableSweets() > numRequiredSweets); } } }); 

Here are my bullying:

 var mockSchedule = { isShopOpen : function() {return true} } var mockWarehouse = { numAvailableSweets: function(){return 10}; } 

Here are my tests:

 expect(shop.canSellSweets(5)).toBe(true); expect(shop.canSellSweets(20)).toBe(false); 
+64
angularjs unit-testing jasmine
Oct 09 '13 at 14:01
source share
8 answers
 beforeEach(function () { module(function ($provide) { $provide.value('schedule', mockSchedule); }); }); 

A module is a function provided by the angular -mocks module. If you pass a string argument, the module with the appropriate name is loaded and all providers, controllers, services, etc. Available for specification. Usually they are loaded using the injection function. If you pass a callback function, it will be called using the Angular $ injector service. This service then accesses the arguments passed to the callback function and tries to determine which dependencies should be passed to the callback.

+51
09 Oct '13 at 14:38
source share

Improving Atilla's response and direct response to KevSheedy's comment, in the context of module('myApplicationModule') you would do the following:

 beforeEach(module('myApplicationModule', function ($provide) { $provide.value('schedule', mockSchedule); })); 
+35
Feb 27 '14 at 13:04
source share

With CoffeeScript, I run some issues, so I use null at the end:

 beforeEach -> module ($provide) -> $provide.value 'someService', mockyStuff: value : 'AWESOME' null 
+7
Feb 03 '14 at 17:15
source share

You can see here for more information.

https://docs.angularjs.org/guide/services#unit-testing

You want to use the $ provide service. In your case

 $provide.value('schedule', mockSchedule); 
+6
Oct 09 '13 at 14:37
source share

I recently released the ngImprovedTesting module, which should facilitate testing in AngularJS mode.

In your example, you will only need to replace Jasmine in your test ...

 beforeEach(module('myModule')); 

... from...

 beforeEach(ModuleBuilder.forModule('myModule').serviceWithMocks('shop').build()); 

For more information about ngImprovedTesting check out his introductory blog post: http://blog.jdriven.com/2014/07/ng-improved-testing-mock-testing-for-angularjs-made-easy/

+1
Jul 29 '14 at 0:22
source share

The easiest way to add a layout to the module is as follows:

  beforeEach(function () { module('myApp'); module({ schedule: mockSchedule, warehouse: mockWarehouse } }); }); 

you can use injection to get a link to these layouts for pre-verification manipulations:

 var mockSchedule; var mockWarehouse; beforeEach(inject(function (_schedule_, _warehouse_) { mockSchedule = _schedule_; mockWarehouse = _warehouse_; })); 
+1
Jun 28 '15 at 18:59
source share

I hope my answer is not so useless, but you can mock $provide.service

 beforeEach(() => { angular.mock.module( 'yourModule', ($provide) => { $provide.service('yourService', function() { return something; }); } ); }); 
0
May 03 '16 at 11:30 a.m.
source share

Since you use jasmine, there is an alternative way to mock calls with jasmine spies ( https://jasmine.imtqy.com/2.0/introduction.html#section-Spies ).

Using them, you can target function calls and, if necessary, enable end-to-end calls. This avoids clogging the top of the test file with $ provision and mock.

At the beginning of each test, I would have something like:

 var mySchedule, myWarehouse; beforeEach(inject(function(schedule, warehouse) { mySchedule = schedule; myWarehouse = warehouse; spyOn(mySchedule, 'isShopOpen').and.callFake(function() { return true; }); spyOn(myWarehouse, 'numAvailableSweets').and.callFake(function() { return 10; }); })); 

and this should work similarly to the $ provision mechanism, noting that you need to provide local instances of the injected variables that will track.

0
Mar 23 '17 at 14:42
source share



All Articles