AngularJs Unit Testing Part 2 – Services with $httpBackend

In my previous post I wrote about how we could test a controller that injects a service that makes an HTTP call to API to return a list of images. I showed how to mock the service but I did not show how to test that service itself. But for various reason, we still do not want our tests to actually make HTTP calls.

We want to mock unit tests API calls for the following reasons:

  • We want fast tests.
  • We don’t want external dependencies for our tests.
  • We just want to make sure we sent the request correctly or not.

Now, let’s take a step back and actually test the service is working as expected. Here is another look at the service we are testing.

Currently we only have one function and in this function I am injecting the $http angular service to make an API call to the server to return a list of images displayed on the homepage.

Again, we have a bit of complexity here because this function make an asynchronous call to the server, so we need a way to handle that and make it run synchronously for the test.

Fortunately, Angular gives a way to mock the actual call through the $http service using a service called $httpBackend.

Here are is the test for this code minus one key detail. That I will show later in this post.

The setup and initial tests:

  • In this test file, I am injecting the service I want to test and the $httpBackend service into the tests by using the “inject” function.
  • I am also checking for errors and uncompleted promises after each test in the “afterEach” function. (I will discuss this feature shortly).
  • I have setup my normal “are you there” tests just to ensure the service and the function I want to test exist.

The testing of the getting data:

  • In the test where I am checking to see if I make the expected API call I setup a spy using the $httpBackend service.
  • The service has a “when” and “expect” function, and I am using the when function. If you use the “expect” function, you are checking that the call is actually made, and will get a failed test if the function is not called correctly. The “when” does not fail the test if the function is not called. With the “when” function I am passing in two parameters:
    • The first parameter I am passing in “GET”, which tells the service that this will be a “GET” request.
    • The second parameter I am passing is the exact URL.
  • The respond function tells the service what you want the response to mocked with.
  • I can then call the service “imageService.getImages()” and the $httpBackend service will mock that call and return a promise.
  • When the promise is resolved, I can then check to see if that data I got back is what I expected.

However, if I run the code like it is now, my test fails. Here is the results of my failed tests.

unflush

The first failure is stating that my data variable is undefined. However, my second failure is stating that I have 1 unflushed request. In essence, this second failure is telling me I have one unresolved promise. I got this second exception because I set the following assertions to run after each test:

So when using $httpBackend, its good to always set these assertions as it can give you helpful information on your failing test.

But this begs the question, “what can I do to fix this test?”

To fix this test I need a way to resolve my promise. I can resolve my promise using the $httpBackend “flush” function.

So to fix this right above the assertion I need to add the following code.

With this in place, now all my tests pass.

flushed

Conclusion

Hope, this helps you write your own unit test, and as in the earlier post, I have updated the code on Github if you want to take a look. The specific spec file is located here.

 

Leave a Reply

Skip to toolbar