Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - What's the point of mocking data via $httpBackend?

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!

like image 932
The_Dude Avatar asked May 02 '16 13:05

The_Dude


People also ask

Why do we use mock data?

Mocking is a way to replace a dependency in a unit under test with a stand-in for that dependency. The stand-in allows the unit under test to be tested without invoking the real dependency.

What is meant by mocking the data?

Mocking is essentially simulating the behaviour of real data in controlled ways. So in order to use mock data effectively, it is essential to have a good understanding of the software under test and more importantly how it uses its data.

What is httpBackend flush?

Flushing HTTP requests For this reason, the mock $httpBackend has a flush() method, which allows the test to explicitly flush pending requests.

Why is mocking used for Testcases in iOS?

Mocking is a key technique when it comes to writing unit tests in pretty much any language. When mocking an object, we are essentially creating a "fake" version of it - with the same API as the real one - in order to more easily be able to assert and verify outcomes in our test cases.


1 Answers

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.

like image 128
ohboy21 Avatar answered Nov 15 '22 05:11

ohboy21