Which URL to use when working with $httpBackend expectGET - angularjs

When expecting a call to the API should I include the entire URL including all the parameters, or do I just need a partial match?
Should I be listening for a call to the exact URL :
http://address.of.api/stuff/123?include=thing,anotherthing.name;
Or do I just need this :
/stuff/123

$httpBackend is part of Angular's Mock environment designed to replace real backend by fake one, or rather by imitating how Angular's $http works without real backend.
As much as I love Angular, I find $httpBackend over-engineered and unnecessarily complicated for what it does:
It is not recommended way to throw complicated code inside your tests. The more you do it, the more chance is that you create errors in that testing code instead of what you are actually supposed to test.
It promotes the bad practice of placing $http (or other low-level services in your abstraction hierarchy) freely around your code, as you can later use that $httpBackend to mock it away.
Instead it works cleaner to isolate any reference to low level methods into dedicated methods of your own, whose single responsibility is to make http requests. These dedicated methods should be able to work with real backend, not a fake one!
More details here on Angular testing

Related

Mocking service in AngularJS HTTP

I'm trying to test a controller that does an http request through a service.
Should I just mock the service and return a default value, rather than doing an actual http request, or using $httpBackend.
I'm testing in Jasmine by the way.
Thanks.
TL;DR Don't do an actual http-request.
UNIT-TESTS
When doing proper unit-tests, you only test a single unit. This can be a class or only a part of a class. This means that you have to mock the dependencies. In your case it would mean that you'd mock the service to simply act as the class would. So returning a promise containing a data-model.
pro: The biggest advantage of true unit-tests is speed. You can perform a huge amount of unit tests instead of a single end-to-end test.
con: The biggest disadvantage of unit-tests is that when you change a dependency to work in a different way, your tests will still succeed because the service has been mocked.
INTEGRATION-TESTS
An integration test works almost a a unit-test, but here you don't mock direct dependencies. In your case, when doing an integration-test, you would not mock the service, rather it's dependencies (with $httpBackend).
pro: Still quite fast, and offers even more robust tests. Because when you update the direct dependencies, the classes you test can fail because they are not mocked.
con: Not quite as fast as an unit-test, but still very fast.
END-TO-END
E2E tests test the entire application, not mocking anything. This includes all XHR-calls to an api.
pro: Since nothing is mocked, it always covers the entire application. And it is very useful to track DOM-changes and browser-compability. It can even automatically take screenshots to give a real view of the rendered data.
con: it's slow. Because it performs actual API-calls these tests can take a while to perform.
So to answer your question, it depends what you're writing. When you write proper unit-tests you should mock the service:
$provide.service('DataService', ['$q', function($q) {
this.get = function() {
return $q(function(resolve, reject) {
if (requestFailed) {
reject('The request failed');
}
resolve(APIData);
});
};
}]);
If you're doing integartion-tests, you should mock the actual $http-request using $httpBackend.
it('should request data', function() {
$httpBackend
.expect('GET', url)
.respond(APIData);
expect($scope.list.count).toEqual(0);
$scope.clickRetrieve();
$httpBackend.flush();
expect($scope.list.count).toBeGreaterThan(0);
});
I'm working on quite a big application an have not to much experience in testing. But my favorite testing-type is by far integration-testing. I've had some issues with unit-tests that didn't reveal breaking changes due to the mocked services. Since I've all but switched to integrated tests, where I mock almost exclusively my data-services.
side-note: I work using data-services which act as a layer between my application and the API, if the API is updated, in theory I should only update the data-service as no class except the repository accesses these.
This way I can ensure that in my application I only work with DataModels instead of simple Objects, and that I use undefined, not null.
use $httpBackend
Since you need to mock the response also
$httpBackend.when("GET",'URL').respond(respnonse);
response contains the value that you are expecting.

Angular ngmock httpBackend - ignore all but one request?

I am new to writing unit tests, so apologies if this is a dumb question. If I'm trying to test a method in an Angular controller that relies on mock data from a service call, and I want to also mock that service call (ngResource), is there a way to make httpBackend ignore other requests made in my controller on initialization?
I've tried placing my whenGET or expectGET definitions in before blocks, and only instantiating my controller within my test, but I always find that httpBackend is expecting other requests (Error: Unexpected request) when I call flush(). I do not want to write mocks for all other requests, just the one I'm using for this test.
Of course, this may be a stupid idea, as I can also just provide the fake data directly, and not test the service along with the controller's method. I've verified that this works. Maybe the correct answer is that I shouldn't be testing services from within a controller.
FWIW, I've also tried using Sinon fakeServer, and apparently it doesn't even pick up on Angular's XHR implementation (the server never responds).

AngularJS Provider dependency injection - using $http in provider?

tl;dr
I'm really struggling to find the appropriate pattern here. How should I best configure a generalized provider to a specific use-case? I can't use $http as a dependency in .configure(); can I?
longer, boring explanation:
I am trying to create a generalized provider which I may reuse in Angular. I have it working, however it requires configuration.
The intention is to provide a fallback REST service to use in saving data to the server, but with provision to save offline in local-storage. Therefore, I need to provide appropriate $http calls for each instance of this provider.
Is it possible to provide appropriate $http calls with .configure() or else should I try and figure out how to inject $http into the provider from the start and then configure it afterward??
It's frustrating... and may change in AngularJS 2.0... But for now, yes, it is not possible to do this. There is a very high wall between the .configure() and .run() states, so you can't access $http from a .configure() function. The reason is that it hasn't actually been created. At this stage, all that exists is the provider. Once all of the dependencies are configured, then the http provider will be used to make the real $http service.
I'm not sure exactly what you're trying to do, but there are two excellent AngularJS developers that are good to follow who have some advanced patterns in projects they've shared: Pascal Precht and Brian Ford. Here are two projects that make heavy use of provider/service concepts as well as $http-driven services:
https://github.com/angular-translate/angular-translate
https://github.com/btford/angular-modal
Angular Modal, especially, does $http work to load its templates. There might be use cases in there that are similar to what you're trying to do.

Best practice for angular service

I have a simple question about best practices.
A service loads once at load time.
Let's say there is a method called getUser in the service called user.
I have to call getUser in several controllers.
The GET request will happen twice right?
Is there a good practice to check whether the data has already been fetched to avoid this second call?
Yes, the call gets executed twice. You can use angular's built in $http cache option, or you could use an existing module like angular-cache, or other libraries such as Breeze or Amplify. You can also try handling it yourself, probably the worst option.

angularjs global timer for inbox

Hi I'm building an angularjs app that has a timer throughout the application. Every minute I will be polling the server to see if a user has gotten a new message in their inbox.
I was wondering what is the best way to design this? I see two options so far:
1.) Rootscope function
2.) A Service
The problem with the service approach is that I have to inject this service to every controller I have. Does anybody else have any suggestions on how to design this app?
Thanks
Use a service - it's a cross-cutting concern that some, but probably not all of your controllers need to know about. Injecting it where it is needed does involve some extra keystrokes at first, but it's a benefit, not a problem - it keeps your code modular and easier to test.
If you use a service, you can inject a stubbed instance into your controller tests so you can test the controllers in isolation. You can use Jasmine spies (for example) to return mock values from your service, so you can easily test how your controllers behave with a range of inputs.

Resources