2

I have quite some experience with TDD in Java and Kotlin and currently try to learn testing with Javascript.

I am not sure if this is really a question about weak vs. strong typing or about general design.

I always was under the impression that mocking/stubbing code you don't own is a bad idea. In Kotlin I would create and interface for the library and implement that interface with a wrapper.

Then inject a mock of my interface into the tests.


In one of the books I am reading the suggestions to test routes
of an express app is to stub the express.Router() class:

const { expect } = require('chai');
const express = require('express');
const sinon = require('sinon');

describe('user routes', () => {
  var sandbox;
  var router;

  beforeEach(() => {
    sandbox = sinon.sandbox.create();
    sandbox.stub(express, 'Router').returns({
      get: sandbox.spy()
    });

    router = require('../src/routes/user');
  });

  afterEach(() => {
    sandbox.restore();
  });

  it('should register GET / route', () => {
    expect(router.get.calledWith('/', sandbox.match.any)).to.be.true;
  });
});

The SUT is:

const express = require('express');

const router = express.Router();

router.get('/', (req, res) => {
  res.send("");
});

module.exports = router;

Is this ok, or is there a better way of doing this?

1

As you point out, one major advantage of wrapping an external dependency in a module that implements a custom interface is that you can easily replace it with a mock implementation.

In weakly typed languages, this is not strictly necessary. You could simply use a mock that provides the same API as the library itself. This saves you the wrapper implementation.

However, testing is not the only advantage such a wrapper provides:

  • The wrapper protects the rest of your application from changes in the library's API

  • You can provide just the functionality you need in the way that's most suitable to the consumer

If you skip the wrapper, you'd forgo all of those advantages as well. Personally, I would keep the wrapper for those reasons. Obviously, you won't need to define an interface in a dynamically typed language.

  • Can you provide a brief code example of what you're talking about in a weakly-typed language that doesn't require interfaces, but which you would provide one anyway? – Robert Harvey Jan 24 '18 at 18:03
  • @RobertHarvey you misunderstood me. I wouldn't provide an interface, but I would still go through a wrapper to access the library functions. I've edited the answer to try to clarify this. – doubleYou Jan 24 '18 at 18:11
  • I'll rephrase. Can you provide a brief code example of the wrapper you're referring to? I assume the wrapper is merely a substitute for the interface that you would otherwise use in a strongly-typed language. – Robert Harvey Jan 24 '18 at 18:35
  • @RobertHarvey basically yes. Instead of lib.doX() you call wapper.doX() which then calls lib.doX(). Then you mock out wrapper, not lib. My point is that this is not required for testing, but that it's IMHO still the best approach for the other benefits of the wrapper. – doubleYou Jan 24 '18 at 19:26

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.