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
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');
});
});
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 ;).
Top comments (2)
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.
True that: one should use them in tandem and not separetely in order to produce relevant tests.