DEV Community

loading...

Using API first and TDD for your next library

khalyomede profile image Khalyomede ・3 min read

I used this technique to help me create more relevant unit tests, and I wanted to share it with you.

If TDD does not sound familiar to you, check this quick but straight to the point post :

TDD might not be the right tool to start with

Let us imagine we are building a node module to check if a date is between two dates. Let us call it is-date-between.

Let us create our unit tests right now.

...

Sounds complicated, isn't it?

API first to the rescue

Let us take another approach: give me an example of usage for this library.

const isDateBetween = require('is-date-between');

const dateToCheck = new Date('2018-12-26');
const pastDate = new Date('2017-01-01');
const futureDate = new Date('2019-01-01');

console.log(isDateBetween(dateToCheck, pastDate, futureDate)); // true
Enter fullscreen mode Exit fullscreen mode

From this we can extrapolate the different issue we want to avoid:

  • the past & future date should not be reverted
  • all the parameters should be date objects
  • the checking should be inclusive

Which would be transcribed into:

const chai = require('chai');
const expect = chai.expect;
const isDateBetween = require('is-date-between');

describe('isDateBetween', function() {
  it('should throw an exception if the past & future dates are reverted', function() {
    expect(function() {
      const dateToCheck = new Date('2018-12-26');
      const pastDate = new Date('2017-01-01');
      const futureDate = new Date('2019-01-01');

      isDateBetween(dateToCheck, futureDate, pastDate);
    }).to.throw('dates are reverted');
  });

  it('should throw an exception if the date to check is not a date object');
  it('should throw an exception if the past date is not a date object');
  it('should throw an exception if the future date is not a date object');
  it('should return true if the date to check is between');
  it('should return false if the date to check is not between');

  describe('inclusive dates', function() {
    it('should return true if the date to check is equal to the past date');
    it('should return true if the date to check is equal to the future date');
  });
});
Enter fullscreen mode Exit fullscreen mode

See, you did it!

Next level: coverage & mutations testing

Testing relies on the human. By definition we are not perfect, we can forget, we can do mistakes, we can be irrelevant or repetitive...

Some tools help you limit this, until Elon Musk have turned us into cyborgs.

Code coverage lets you check which part of your code is left untested. This helps you cover a maximum of cases. I like nyc because it works well with mocha.

Mutations testing is a powerful tool to check if you tested the right parts of your code. It will change a little bit your source file and check if some tests fail: if not, you might have passed over some tests that would have not let the mutations pass through your tests. Pretty cool to help us reach a high level of quality in your unit tests. I like stryker a lot.

In conclusion

Testing in 2019 should not be scary, but accessible. I think we tend to make things a lot more complicated than they appear to be in real. I hope API first will give you the desire to start using testing if you never did before.

Testing will require a bit more time, but this is a time you will earn when scaling for more features and fixes. It can actually make you more confident over next releases of your products, because you can rely on tests to build solid basis.

If you ever thought

Better not touch this part of the code, this is too complicated and could break if we add something.

Maybe this is the right time to think of unit tests ;).

Discussion (2)

pic
Editor guide
Collapse
nssimeonov profile image
Templar++

API first - working only on theory. In reality when you start implementing the UI, you have to change a lot in the API, so better work on both at the same time.

Collapse
khalyomede profile image
Khalyomede Author

True that: one should use them in tandem and not separetely in order to produce relevant tests.