2

Is it better to unit test using a mock library like 'nock' (nodejs) or to just test the server's http requests directly?

Here is an example of my Express server test for testing if my server is up and testing for yelp data being served from my server.

test.js:

describe('Express server', () => {
  let request;

  beforeEach(() => {
    request = chai.request(app);
  });
  it('It runs', (done) => {
    request.get('/').end((err, res) => {

      expect(res).to.have.status(200);

      done();
    });
  })

  it('/post serves yelp data', (done) => {


    //  let yelp = nock('localhost:8080').post('/post', mockplace)
    let mockPlace = [
      {
        name: 'Le Thai',
        coords: {
          lat: 36.168743,
          lng: -115.139866
        }
      }
    ];

    let expected = {
      name: 'Le Thai',
      img: 'https://s3-media1.fl.yelpcdn.com/bphoto/vYnAqILo37UXrNvz_5QX0Q/o.jpg',
      hours: false,
      revcount: 1425,
      rating: 4,
      price: '$$',
      location: '523 Fremont St,Las Vegas, NV 89101',
      phone: '(702) 778-0888',
      url: 'https://www.yelp.com/biz/le-thai-las-vegas?adjust_creative=euqH0_vzVDHpkWNkOrRvRg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=euqH0_vzVDHpkWNkOrRvRg'
    }

    request.post('/post').set('content-type', 'application/json').send(mockPlace).end((err, res) => {

      assert.deepEqual(res.body[0], expected);
      done();
    })

  })
});

I've tried testing in both ways described above, and have noticed that using a mock service like nock dramatically decreases the test suite run time. Would this be the only reason to use a mock service?

If I'm using a mock service, then what is the point of doing the testing in the first place?

2
  • Are you familiar with Test Doubles? – Laiv Feb 25 '18 at 9:00
  • 1
    I think so. Maybe someone thougth you were asking for support about your test framework. I'm writing a answer tho. – Laiv Feb 25 '18 at 9:15
3

Since we speak about unit test, the likely answer is yes, we should mock remote calls. Or better said, we should isolate the code under test from external inferences. I said mock but for this case, maybe, it would be good to speak about stub instead.

Long story short, unit tests are supposed to be tests addressed to guarantee the proper behaviour of one or more specific components, in order to gain confidence in their behaviour. To this end, we need these tests to be deterministic.

For achieving determinism we usually isolate the components under test from external inferences that might cause the test to fail *. We only want to prove the rightness of small pieces of code independently from interactions with other pieces. This is important because we want to be able to execute these tests anytime, quickly and get always the expected result. Ultimately, unit tests are the first defence against changes that cause unexpected (and malicious) side-effects.

As I said, we want them to be fast a couple reasons:

  • They are numerous (compared with integration tests and others)

  • We want to be capable to execute them by hand any time without eroding our productivity.

  • Ideally, unit tests are executed every time we build the project. If we aim to go continuous integration and continuous delivery, the quickness of the building phase matters since it conditions the time-to-market **.

How testing against real integrations affects determinism and quickness?

The remote services we integrate with might change or fail anytime, causing our tests no longer to be deterministic. Additionally, real integrations might slow down the timings of the tests, causing the building phase to take longer, eroding the productivity and potentially, the time-to-market.

then what is the point of doing the testing in the first place?

The point is testing code against a specific contract version. Usually the latest at the moment of the integration.

However, as Heraclitus said "The only thing is constant is change". Contracts are not an exception. They can change and they could do it without our agreement. So, while the future remains unknown, the present requires us to test our code against the current contracts without missing: determinism, predictiveness and quickness.

That said, it doesn't mean we cannot perform tests with real integrations. We can, but these tests are not considered to be unitary. For further reading about this subject take a look at the link.

Further readings


* Overall from those we have no control

**There could be involved opportunity costs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.