AngularJS jasmine service mock - javascript

There seems to be several ways to stub out services when testing Angular controllers using Jasmine.
One of the ways I've become accustomed to is to do the following in a beforeEach block:
mockService = {}
inject( $controller) ->
controller = $controller('MyController', {
MyRealService: mockService
})
Another way is to use $provide to stub my dependency injected service:
module('app', ($provide) ->
mockService = {}
$provide.value('MyService', mockService)
)
When I had:
afterEach ->
httpBackend.verifyNoOutstandingExpectation()
in my test. Only the $provide method worked, and the $controller style would not. Using $controller the test was somehow hitting MyRealService and including all of its dependencies, rather than ignoring and using mockService. Without the verifyNoOutstandingExpectation(), both methods seem to behave the same and the test passes.
What are the main differences between the 2 styles? When should you be using one over the other? Any ideas why the effect of stubbing is different in the presence of a verifyNoOutstandingExpectation()

What are the main differences between the two styles?
In the first case, we inject our fake objects ourselves into the controller, whereas with the second method we tell Angular where it can find the fakes when it needs to inject them later.
When should you be using one over the other?
I prefer the first method as it is more obvious, and especially when we test controllers, it is sufficient.
I mostly use the $provide method when dealing with services/factories or routing testing. Since services can't be "newed up" like controllers, we need to trick the inject function to use our fakes using the provider.
And in the case of testing routing we have no other possibility than using the provider to stub out the services used in the route resolvers.
Any ideas why the effect of stubbing is different in the presence of a verifyNoOutstandingExpectation()
Not really sure on how to answer this one, but I have found $httpBackend to be not-so-obvious to use. Especially when testing routes. It records all traffic, including things like calls to templates defined in a route etc, which makes it very easy to overlook a call in the setup.

Related

AngularJs defining global variables

What is the best way to define a global varible in AngularJS?
I know there are plenty of solutions about this topic, the most commom:
Use a service;
Use $rootScope;
I want an answer for a different context. For example:
A commom url used for multiple requests in multiple services: my/folder/class.php;
The name of a main module: myApp;
A commom alert message for an error: Failed to connect to the server, try again.
Things that will be used all over the app, in different situations and will never change.
Looking around the internet I saw 2 other possibilities other then $rootScope and services:
Use AngularJS constants;
Use JS var outside of the main ng module;
So my question is: For the AngularJs scenario, what is the best alternative?
Do we really use constants for this situation? Is there any other provider for this purpose. Also I'd like to know whats the performance impact of the, if any.
For true constants use Angular constants. If your values may need to be configured or calculated use an Angular service and expose getter functions. For strings you may want to consider localization, so use one of the Angular localization libraries to store these (I use Angular-localize).
Hope this is helpful.

Why do Services, Constants, Etc Need to be Injected?

Let's say I create an AngularJs service. I attach it to my module:
angular.module('fooModule').service('myService', function(){
var service = {
logSomething: function() {
console.log('Service logged something');
}
};
return service;
});
Whatever. It's there - same with constants, factories, providers, etc. Why do I need to then inject this service, constant, etc into my controllers? Is it essentially the same principle as "using" in C# - the only purpose being avoiding conflicting variable/function names? That doesn't seem to make sense since I still have to write myService.logSomething() which clears up the whole namespace issue.
Or does it somehow speed up loading? I don't see how that would be though.
You haven't actually injected this service into anything yet; it is just a singleton at this point. You have registered it with your angular module, yes, but nothing else in your module knows about it. It's not available until you actually inject it. In a very abstract way, you could think about dependency injection in Angular like using or import, but it's really more like supplying an initializing variable in a constructor (actually, this is exactly what it is).
If you are wondering why dependency injection might be a good design practice in general, this post should be of interest to you.

$injector.get is causing the Angular module's run() method to be called every time

I have a need to manually get things from the angular $injector.
I've been going:
var injector = angular.injector(['app.service', 'ng']);
var myService = injector.get('myService');
This worked great. But I've since noticed a problem, the app.service module's run() method is being called everytime I call angular.injector. I had things in there which initialised my app, which are now being run too many times.
Should I move my app bootstrapping logic out of the run() method, or is there another way to get the $injector without having the run() method called?
I'm also a bit concerned calling the injector a lot is bad for performance?
The documentation may be unclear on that, but angular.injector indeed initiates the whole module with config and run blocks (otherwise you would run across the issues with app components that depend on these blocks).
The instances of module services (including $rootScope) also won't be the same as the ones within bootstrapped app.
You are free to divide the module the way its services would be easy to use, but keep in mind that you won't be able to interact with running Angular app. If you need to use the same code inside and outside Angular, then define it outside.
If you need to interact with running app instead, then do
var injector = angular.element(document).injector();
instead, as the documentation suggests.
I'm also a bit concerned calling the injector a lot is bad for
performance?
Sure, there would be some RAM and CPU overhead , its severity totally depends on your module.

AngularJS - module().provider() vs $provide.provider()

Note: I'm not seeking the differences between the value, factory, service, and provider 'recipes', as explained here.
I'm looking for clarification on the different ways to define them: Correct me if I'm wrong, but it appears as though
myApp = angular.module('myApp', [])
.value(...)
.factory(...)
.service(...)
.provider(...)
map to
$provide.value()
$provide.factory()
$provide.service()
$provide.provider()
And you can use either way. I asked this question, and realize I can use $provide as a dependency to module().config(). My questions:
When/why would I use angular.module().provider() vs using the $provide dependency?
Is there any way (or reason) to access/change a provider after definition?
Using AngularJS Batarang for Chrome, I'm looking at the various angular $scope properties, and don't see $provide or $injector. Where do these live?
The provider methods off the module definition are just short cuts. Use them as often as you like because it leads to shorter, easier to read and understand code. Less ritual/ceremony is involved than injecting the $provider service and calling that directly. The main reason to use $provide directly is to access a method on it that is not a short cut from module (such as the decorator) or if you have to do something from within a service or component that is not up at the module definition level.
The common case for changing a provider after it's definition is when you are integrating a third-party component and want to add or change the behavior. The third-party module will define the service and then you step in and override or extend it in some way that is specific to your app. A common case for example is to take the built-in Angular exception handler and extend that to interface with your own components.
$scope is a special "glue" used for data-binding and only exposes properties/functions that you explicitly set on the $scope. All of the other miscellaneous modules/services are stored within Angular's dependency injection container. The very first thing Angular does is create an $injector instance to keep track of dependencies. Therefore $injector === $injector.get('$injector'). Same with $provide. Anything prefixed with a $ is by convention a service that Angular places in the $injector for you to use.

How to use Angular.js service instance inside module config and keep the same instance

I am trying to use an service inside my app module config and a little research pointed that I need to do it using an injector.
This works pretty fine, except that when the service is loaded inside the controllers it is not the same instance anymore as the one previously loaded by the injector.
Does anyone know how to get the same instance? Or is there a better way to do it?
I created a plnkr to show the behavior: http://plnkr.co/edit/BGUa3H
From the doc - Services as singletons
All Angular services are application singletons. This means that there
is only one instance of a given service per injector. Since
Angular is lethally allergic to global state, it is possible to create
multiple injectors, each with its own instance of a given service, but
that is rarely needed, except in tests where this property is
crucially important.
It mean if you do injector.get for a single injector, it will always returns the singleton like this
var injector = angular.injector(['app.services']);
var singletonService1 = injector.get('singletonService');
var singletonService2 = injector.get('singletonService');
console.log(singletonService1 === singletonService2) // prints true
However if you inject it to another the controller in the meantime, a brand new instance will be created.
Hope it helps.

Categories