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!
You have to differentiate somehow between:
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.