Categories: ProgrammingTutorials

Light Speed Unit Testing

5 min read

In this article by Paulo Ragonha, author of the book Jasmine JavaScript Testing – Second Edition, we will learn Jasmine stubs and Jasmine Ajax plugin.

(For more resources related to this topic, see here.)

Jasmine stubs

We use stubs whenever we want to force a specific path in our specs or replace a real implementation for a simpler one.

Let’s take the example of the acceptance criteria, “Stock when fetched, should update its share price”, by writing it using Jasmine stubs.

The stock’s fetch function is implemented using the $.getJSON function, as follows:

Stock.prototype.fetch = function(parameters) {
$.getJSON(url, function (data) {
   that.sharePrice = data.sharePrice;
   success(that);
});
};

We could use the spyOn function to set up a spy on the getJSON function with the following code:

describe("when fetched", function() {
beforeEach(function() {
   spyOn($, 'getJSON').and.callFake(function(url, callback) {
     callback({ sharePrice: 20.18 });
   });
   stock.fetch();
});
 
it("should update its share price", function() {
   expect(stock.sharePrice).toEqual(20.18);
});
});

We will use the and.callFake function to set a behavior to our spy (by default, a spy does nothing and returns undefined). We make the spy invoke its callback parameter with an object response ({ sharePrice: 20.18 }).

Later, at the expectation, we use the toEqual assertion to verify that the stock’s sharePrice has changed.

To run this spec, you no longer need a server to make the requests to, which is a good thing, but there is one issue with this approach. If the fetch function gets refactored to use $.ajax instead of $.getJSON, then the test will fail. A better solution, provided by a Jasmine plugin called jasmine-ajax, is to stub the browser’s AJAX infrastructure instead, so the implementation of the AJAX request is free to be done in different manners.

Jasmine Ajax

Jasmine Ajax is an official plugin developed to help out the testing of AJAX requests. It changes the browser’s AJAX request infrastructure to a fake implementation.

This fake (or mocked) implementation, although simpler, still behaves like the real implementation to any code using its API.

Installing the plugin

Before we dig into the spec implementation, first we need to add the plugin to the project. Go to https://github.com/jasmine/jasmine-ajax/ and download the current release (which should be compatible with the Jasmine 2.x release). Place it inside the lib folder.

It is also needed to be added to the SpecRunner.html file, so go ahead and add another script:

<script type="text/javascript" src="lib/mock-ajax.js"></script>

A fake XMLHttpRequest

Whenever you are using jQuery to make AJAX requests, under the hood it is actually using the XMLHttpRequest object to perform the request.

XMLHttpRequest is the standard JavaScript HTTP API. Even though its name suggests that it uses XML, it supports other types of content such as JSON; the name has remained the same for compatibility reasons.

So, instead of stubbing jQuery, we could change the XMLHttpRequest object with a fake implementation. That is exactly what this plugin does.

Let’s rewrite the previous spec to use this fake implementation:

describe("when fetched", function() {
beforeEach(function() {
   jasmine.Ajax.install();
});
 
beforeEach(function() {
   stock.fetch();
 
   jasmine.Ajax.requests.mostRecent().respondWith({
     'status': 200,
     'contentType': 'application/json',
     'responseText': '{ "sharePrice": 20.18 }'
   });
});
 
afterEach(function() {
   jasmine.Ajax.uninstall();
});
 
it("should update its share price", function() {
   expect(stock.sharePrice).toEqual(20.18);
});
});

Drilling the implementation down:

  1. First, we tell the plugin to replace the original implementation of the XMLHttpRequest object by a fake implementation using the jasmine.Ajax.install function.
  2. We then invoke the stock.fetch function, which will invoke $.getJSON, creating XMLHttpRequest anew under the hood.
  3. And finally, we use the jasmine.Ajax.requests.mostRecent().respondWith function to get the most recently made request and respond to it with a fake response.

We use the respondWith function, which accepts an object with three properties:

  1. The status property to define the HTTP status code.
  2. The contentType (JSON in the example) property.
  3. The responseText property, which is a text string containing the response body for the request.

Then, it’s all a matter of running the expectations:

it("should update its share price", function() {
expect(stock.sharePrice).toEqual(20.18);
});

Since the plugin changes the global XMLHttpRequest object, you must remember to tell Jasmine to restore it to its original implementation after the test runs; otherwise, you could interfere with the code from other specs (such as the Jasmine jQuery fixtures module). Here’s how you can accomplish this:

afterEach(function() {
jasmine.Ajax.uninstall();
});

There is also a slightly different approach to write this spec; here, the request is first stubbed (with the response details) and the code to be exercised is executed later.

The previous example is changed to the following:

beforeEach(function() {
jasmine.Ajax.stubRequest('http://localhost:8000/stocks/AOUE').andReturn({
   'status': 200,    'contentType': 'application/json',    'responseText': '{ "sharePrice": 20.18 }' });   stock.fetch(); });

It is possible to use the jasmine.Ajax.stubRequest function to stub any request to a specific request. In the example, it is defined by the URL http://localhost:8000/stocks/AOUE, and the response definition is as follows:

{
'status': 200,
'contentType': 'application/json',
'responseText': '{ "sharePrice": 20.18 }'
}

The response definition follows the same properties as the previously used respondWith function.

Summary

In this article, you learned how asynchronous tests can hurt the quick feedback loop you can get with unit testing. I showed how you can use either stubs or fakes to make your specs run quicker and with fewer dependencies.

We have seen two different ways in which you could test AJAX requests with a simple Jasmine stub and with the more advanced, fake implementation of the XMLHttpRequest.

You also got more familiar with spies and stubs and should be more comfortable using them in different scenarios.

Resources for Article:


Further resources on this subject:


Packt

Share
Published by
Packt

Recent Posts

Harnessing Tech for Good to Drive Environmental Impact

At Packt, we are always on the lookout for innovative startups that are not only…

2 months ago

Top life hacks for prepping for your IT certification exam

I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…

3 years ago

Learn Transformers for Natural Language Processing with Denis Rothman

Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…

3 years ago

Learning Essential Linux Commands for Navigating the Shell Effectively

Once we learn how to deploy an Ubuntu server, how to manage users, and how…

3 years ago

Clean Coding in Python with Mariano Anaya

Key-takeaways:   Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…

3 years ago

Exploring Forms in Angular – types, benefits and differences   

While developing a web application, or setting dynamic pages and meta tags we need to deal with…

3 years ago