6

I just started writing my first unit tests in AngularJS via Jasmine.

Somehow I still do not understand why I should mock the $httpBackend. To make clear what's still unclear to me I will write down a small example:

Imagine I have a service (myService) that's getting data from an URL:

 function getData() {
    return $http.get("http://example.com/data")
       .then(function (response) {
          return response.data;
        });
 }

Let's assume that a GET call to the URL "http://example.com/data" returns following data:

{
    firstname: "John",
    lastname: "Doe"
}

The corresponding test would look like this:

describe("Service: myService", function () {

    beforeEach(module("myApp"));

    var myService, $httpBackend;

    beforeEach(inject(function (_myService_, _$httpBackend_) {
        myService = _myService_;
        $httpBackend = _$httpBackend_;
    }));

    afterEach(function () {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it("should get data", function() {
        var mockData = {datakey: "datavalue"};
        $httpBackend.whenGET("http://example.com/data").respond(mockData);

        var promise = myService.getData();
        $httpBackend.flush();

        promise.then(function(response){
            expect(response).toEqual(mockData)
        });
    })
});

Unless I am mistaken, the test should pass, although the mocked data is not equal to the real data. The test would always pass, no matter how I set the mocked Data, because the service function would always be redirected to what's set in $httpBackend.whenGET("http://example.com/data").respond(mockData);.

I thought the purpose of such a test is to check if the returned data from a GET call [in this case myService.getData()] is REALLY the expected data and not some random mocked data. So whats the actual point of mocking data instead of checking if myService.getData returns the real data {firstname: "John", lastname: "Doe"}?

I'm well aware that I could also set the mocked Data to {firstname: "John", lastname: "Doe"}, but when the real data from the URL would be dynamic, the mocked Data and the real data wouldn't be equal again.

Thank you in advance!

The_Dude
  • 397
  • 1
  • 3
  • 16

1 Answers1

3

You have to differentiate somehow between:

  • Unit tests
  • Integration tests
  • End-to-End tests

What you want is to unit test the getData() function. I assume you don't care if the data is right in this case or not. What you want to test is if the right URL is getting called.

So you are making sure this unit of your code is working as expected.

Take this example:

var add = function(endpoint) {
  var sum = 0;
  endpoint().then(function(numberArray) {
    numberArray.forEach(number) {
      sum = sum + number;
    }
   });

   return sum;
}; 

When you mock the httpBackend here, you actually don't care if you get a 1,2,3 or 5,6,7 back. You want to make sure you add whatever number comes, you add them up and return them.

Your case is much simpler, so you can test if the URL is right, and that's it.

An End-to-End test would also include a proper backend and checks if the data is ok.

The AngularJS documentation makes it clear:

 it('should fetch authentication token', function() {
   $httpBackend.expectGET('/auth.py');
   var controller = createController();
   $httpBackend.flush();
 });

In this example, you want to make sure you are calling the right URL/endpoint. If you really get the right token, an integration test or end-to-end test is more appropriate which calls the real backend then.

ohboy21
  • 4,259
  • 8
  • 38
  • 66
  • So whenever I am testing http GET requests in a unit test, the goal is to check if the right URL is getting called and not if the correct data is beeing set? – The_Dude May 02 '16 at 16:55
  • From my experience and my readings, yes! A unit test means you are testing the functionality of a function, a unit of your application. How the data looks like is mostly not part of it, since the function should react accordingly to it (throw erros etc.) – ohboy21 May 02 '16 at 20:40
  • Thank you for your time. But then I am still wondering why someone would use (like in a lot of tutorials about $httpBackend) mock data and compare it with the data from the corresponding function thats making the http request instead of just checking whether or not the URL gets called (like in your example above). Here a Plunker to demonstrate what I mean: http://plnkr.co/edit/XcWySIWtIJ3QCIOB0iJB?p=info – The_Dude May 02 '16 at 21:11
  • 1
    Well, you can use the tests also as a documentation. Could also be a convience thing that they want to have the same structure of the data in the test, so they just implement that. Again, you are right, from your point of view, it doesn't make much sense. You will see many strange examples in Unit testing with Angular.... – ohboy21 May 03 '16 at 04:59