Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unit test HTTP requests?

As the title asks how do I test HTTP requests with Mocha and Chai?

I've recently started learning unit testing and I'm still getting confused with certain aspects of testing. I can get by fine testing methods that return a value but I'm confused on how to test methods that make HTTP/IO requests.

For example I have the following code:

module.exports = someRequest => new Promise((resolve, reject) => 
    http.get('http://google.com', resp => {
        if(resp.headers['content-type'] !== 200) {
            reject(new Error('Failed to connect to Google'));
        }
        resolve('Connected to Google');
    })
);

I want to test 2 cases:

  1. The request to Google succeed
  2. The request to Google failed

Do I have to mock these requests and if so what's the purpose of mocking a method that is intended to make a HTTP request?

like image 868
BugHunterUK Avatar asked Oct 02 '17 18:10

BugHunterUK


2 Answers

How about mocking http.get with something like that ?

const createHttpGetMock = (expectedStatus) => {
  return httpGetMock = (address) => {
    return new Promise((resolve, reject) => {
      resolve({
        status: expectedStatus,
        headers: {
          // ... headers
        },
        // mock response
      })
    })
  }
}

Then your test could look like this :

describe("Google request", () => {
  it("Resolves when google responds", async () => {
    const httpSuccessMock = createHttpGetMock(200);
    // Inject your mock inside your request function here, using your favorite lib

    const message = await fetchGoogle();
    assert.equals(message, 'Connected to Google');
  })

  it("Rejects when google responds with error", async () => {
    const httpSuccessMock = createHttpGetMock(500);
    // Inject your mock inside your request function here, using your favorite lib

    const message = await fetchGoogle();
    assert.equals(message, 'Failed to connect to Google');
  })
});

This would fulfill the basic contract of a good unit test : regardless of external modules and dependencies, it ensures the module you're currently testing has the correct behaviour in each possible case.

like image 83
aurelienshz Avatar answered Sep 19 '22 06:09

aurelienshz


Here is an example of test with mocha and chai. We also need sinon to stub the http library.

http://sinonjs.org/releases/v1.17.7/stubs/

// test.js

const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const http = require('http');

const someRequest = require('./index');

describe('some request test', function() {
  let httpGetStub;

  beforeEach(function() {
    httpGetStub = sinon.stub(http, 'get'); // stub http so we can change the response
  });

  afterEach(function() {
    httpGetStub.restore();
  });

  it('responses with success message', function() {
    httpGetStub.yields({ headers: { 'content-type': 200 }}); // use yields for callback based function like http.get
    return someRequest().then(res => { 
      expect(res).to.equal('Connected to Google');      
    });
  });

  it('rejects with error message', function() {
    httpGetStub.yields({ headers: { 'content-type': 400 }});
    return someRequest().catch(err => { 
      expect(err.message).to.equal('Failed to connect to Google');      
    });
  });
})

Hope it helps.

like image 26
deerawan Avatar answered Sep 20 '22 06:09

deerawan