3

I'm going through the AngularJS tutorial step 5, and came across this snippet in the testing section:

describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){
  var scope, ctrl, $httpBackend;

  // Load our app module definition before each test.
  beforeEach(module('phonecatApp'));

   // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
   // This allows us to inject a service but then attach it to a variable
  // with the same name as the service.
   beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
   $httpBackend = _$httpBackend_;
   $httpBackend.expectGET('phones/phones.json').
     respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);

    scope = $rootScope.$new();
    ctrl = $controller('PhoneListCtrl', {$scope: scope});
}));

I don't fully understand the purposes of the underscore when injecting $httpBackend. I see the comment and understand what the code is doing. I just don't get why we are only doing this with $httpBackend.

There are two other services we are injecting right along with it that don't need to be injected this way. How are we helping ourselves by injecting $httpBackend in a roundabout manner then immediately assigning it to a variable of the same name, couldn't we just inject it directly?

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
Tim Lindsey
  • 727
  • 1
  • 7
  • 18
  • Thanks, I did read that response, but it strikes me as just a rephrase of the explanation in the code comments (it explains what it's doing, but not why we're doing it). My question is what advantage are we gaining by passing it in with underscores then immediately assigning it to a variable of the same name vs just injecting it directly (without the underscores). – Tim Lindsey Feb 24 '14 at 13:56
  • Because, using this technique, `$httpBackend` injected with the `inject` function becomes available in the outer scope (the `describe`scope). – asgoth Feb 24 '14 at 14:56

2 Answers2

2

Because that way you can declare $httpBackend in your describe, assign the injected service to it in a beforeEach and use it in your it blocks.

example:

describe('PhoneCat controllers', function() {
    var $httpBackend; // variable declaration

     beforeEach(inject(function(_$httpBackend_) {
       $httpBackend = _$httpBackend_; // assignment
     }));

     it('should do something', function(){
        // usage
        $httpBackend.expectGET('/myurl').respond(function(){
            // some behaviour
        });
        // some assertion
     });
});
Chris Bier
  • 14,183
  • 17
  • 67
  • 103
kamilkp
  • 9,690
  • 6
  • 37
  • 56
  • Ok, so it's essentally just to allow you to access it throughout the describe block, right? It would be lost in the beforeEach if we injected it directly instead of using the format above? – Tim Lindsey Feb 24 '14 at 14:01
  • Yes, or you would have to assing it to a variable of different name which would work just fine, but might look odd. Basically you can achieve the same effect in several ways. Another would be: `beforeEach(inject(function($injector) { $httpBackend = $injector.get('$httpBackend'); }));` – kamilkp Feb 24 '14 at 14:18
1

As you must know now, angular $injector simply ignores those underscores, so for injection purposes $httpBackend and $httpBackend are the same. The current implementation simply replaces those underscores.

The only "advantage" is that if you use underscores in your parameters, for instances, $httpBackend you are free to use a global test variable with the name $httpBackend, otherwise you have to give your variables other name

var $httpBackend;

beforeEach(inject(function(_$httpBackend_) {
    $httpBackend = _$httpBackend_;
}));
yeraycaballero
  • 1,603
  • 3
  • 19
  • 29