# Stubbing HTTP Requests With Sinon

This tutorial details how to stub HTTP requests with Sinon.js during test runs.

If you’re developing for the web, you are most likely connecting to some other external service to extend the functionality of your application. You could be connecting to a third-party API - like Twilio, GitHub, Twitter, or Mailgun, to name a few - or just communicating with another service in your microservice stack. Regardless, when unit testing, you do not want HTTP requests to go out to these services. Instead, you can “fake” the request and response with a stub, tricking the system into thinking the request was made.

#### NPM Dependencies:

1. Node v8.7.0
2. Mocha v4.0.1
3. Chai v4.1.2
4. Sinon v4.1.1
5. Request v2.83.0

## Contents

1. Objectives
2. Why Stub?
3. What is a Stub?
4. Project Setup
5. Sinon Setup
6. Testing the Movie Service
7. Conclusion

## Objectives

By the end of this tutorial, you will be able to…

1. Describe what a stub is and why you would want to use them in your test suites
2. Discuss the benefits of using Sinon to stub calls to external services
3. Set up a testing structure with Mocha, Chai, and Sinon
4. Write full integration tests to call an external service during the test run
5. Refactor integration tests to unit tests, stubbing out the external HTTP requests
6. Stub each of the CRUD functions from an external service

## What is a Stub?

In testing land, a stub replaces real behavior with a fixed version. In the case of HTTP requests, instead of making the actual call, a stub fakes the call and provides a canned response that can be used to test against.

It’s important to note that you should not rely solely on fake data in place of real data when testing. At some point in the testing process, possibly in a staging/pre-prod environment, you should test out all external communication so that you can be confident that the system works as expected. This is often achieved with some form of end-to-end tests.

Also, keep in mind, that it can be quite difficult to keep the testing behavior aligned with the actual behavior of the service. It’s common for this to happen when a service is updated and the stub stays the same. Because of this, you should limit your use of stubs to I/O operations and processes that are CPU intensive.

For more on stubs and fakes, check out the excellent Mocks Aren’t Stubs article.

## Why Stub?

Calling external services during test runs can cause a number of problems:

1. First off, this will slow down your test suite. Calling external services, especially in a microservice stack, can result in a ping-pong affect with HTTP requests and responses.
2. Tests will often fail due to network outages and other connectivity issues, like the service being down.
3. Often, third-party services have rate limits in place. Getting around this can be tricky (creating new test accounts on the fly) or costly (upgrading to the next service tier).
4. The service itself may not have a staging or sandbox mode for testing. In this case, you would actually be testing a service in production, so extra care needs to be taken to prevent test data from polluting production data.
5. Finally, the service itself may not be fully implemented or it may not even exist yet, which is common in a microservice stack.

Isolating tests by stubbing external service calls makes testing faster, simpler, and more predictable.

## Project Setup

Let’s start by spinning up the external service that we’ll consume from for testing purposes in the integration tests.

### Movie Service

Clone down the project and install the dependencies:

Take a quick look at the code. This is just a simple Node RESTful API, with the following routes:

URL HTTP Verb Action
/api/v1/movies GET Return ALL movies
/api/v1/movies/:id GET Return a SINGLE movie
/api/v1/movies/:id PUT Update a movie
/api/v1/movies/:id DELETE Delete a movie

Want to learn how to build this project? Check out the Building a RESTful API With Koa and Postgres blog post.

With Postgres up and running on port 5432, open psql in the terminal, and create the databases:

Apply the migrations and seed the database:

Fire up the service:

Then, navigate to http://localhost:1337/api/v1/movies in your favorite browser, and you should see all the movies:

With that, let’s set up the testing framework boilerplate.

### Mocha and Chai

Clone down the base project:

Then, check out the v1 tag to the master branch and install the dependencies:

Make sure the tests pass:

Take a quick look at the project structure before moving on.

## Sinon Setup

Install:

While that’s installing, do some basic research on the libraries available to stub (or mock) HTTP requests in Node. How does Sinon compare to these other libraries?

Here, we stubbed out the greaterThanTwenty function, overriding the function’s default behavior, so that it returns 'something' instead of either true or false.

Run the tests to ensure they pass:

You can also stub a prototype method:

Again, make sure the tests pass:

For more examples, review the official docs.

With that, let’s now look at stubbing HTTP requests.

## Testing the Movie Service

Create a new file in “test” called movie.service.test.js:

So, we’ll test out the movie service using both unit and integrations tests so you can see the difference. Take note of the beforeEach and afterEach functions. Here, we stubbed the get method, from the request package (assigning it to this.get so we can reference it later in the test cases), in the beforeEach(), and then we restored the original behavior in the afterEach().

Install the Request library:

### GET All Movies

Take note of the code comments. This should be fairly straightforward. With the movie service up and running, ensure the test passes:

Now, let’s look at how to stub the HTTP request call. Update the “when stubbed” describe block, like so:

Here, we use the yields method to automatically call the callback passed to get(). Remember how request works? After the request is sent, the function waits until the callback is called before proceeding. So, by stubbing this out, we simply pass in a dummy object and immediately call the callback.

Make sure the tests pass:

Now, how do we know the call wasn’t actually made?

1. Kill the movie service server
2. Add a .only to the describe block - describe.only('when stubbed', () => {

Test again. It should still pass. Once done, remove the .only and fire the movie service back up.

### Fixture

To keep things clean in the test cases and to make it easy to find and update the fake objects, let’s create a test fixtures file.

Add a new folder to “test” called “fixtures”, and then add a new file to that folder called movies.json:

Import the file into movies.service.test.js:

Update this.get.yields:

Make sure the tests still pass!

You may also want to add the expected data for the assertions to the fixtures as well. Or: You could take it a few steps further and generate the actual test cases from the fixture file. Try this on your own.

### GET Single Movie

#### Integration test

Notice how we used the movie id of 4 in the first test. This makes for a brittle test, since it will fail if that movie is removed or the name is updated in the movie service. Sure, we do have control over the data in this service, but in most cases you will not have this luxury.

#### Unit test

Add the fixture to the movies.json file:

Run the tests:

### POST

#### Integration test

Run the tests. They should pass the first time, but if you run them again, you should see the first test, should return all movies, fail:

How can we fix this?

1. Remove the assertion altogether from the first test case
2. Add a beforeEach that removes any test data that was added from a previously ran test case (this will add additional requests, slowling down the test suite even more)

Either way, this is not an easy issue to fix, especially if it’s a third-party service that you have no control over. This is one of the reasons why we’re stubbing in the first place - to limit the complexity. So, instead of trying to fix the integration test, let’s just remove it and focus solely on the unit tests:

#### Unit Test

Next, stub the post method:

Make sure the tests pass:

What if the payload does not include the correct keys? Update the fixture:

Add a new it block:

Fixture:

Stub:

Tests:

### DELETE

Fixture:

Stub:

Test:

Run the tests one final time to ensure they all pass:

## Conclusion

You should now have a better understanding of both the why and how in terms of stubbing with Sinon. Even though this post focused on HTTP requests, you can apply the same logic to other areas of your application like client-side AJAX requests, database queries, and Redis lookups, to name a few.

Turn back to the objectives. Read each aloud to yourself. Can you put each one into action?

Finally, it’s important to stub HTTP calls to external services to avoid flaky tests, speed up the overall test suite, and make testing more predictable. Be sure to balance your stubbed tests with end-to-end tests in a staging environment to ensure the system works as expected.

Grab the final code from the mocha-chai-sinon repo. Cheers!