10. Create your first automated test to cover the public interface
filipedeschamps opened this issue · comments
Now things starts to become exciting. Understand how to do automated tests is a must if you want to consider yourself a good developer.
Assertion library
We are going to use Mocha as our test runner, but first we need an assertion library. An assertion library is responsible to compare values, for example, expect that variable A has the value X, and if it doesn't, throw an error to mark that test as failed.
We will use chai, which is one of the best in town:
$ npm install --save-dev chai
Test runner
Like said before, we will use Mocha to run our tests scenarios:
$ npm install --save-dev mocha
Unit tests
We are ready to write our first unit test. Our objective here is to ensure we are correctly creating an instance and it has all the public methods we coded before.
Create a file called test/unit/rss-feed-emitter.spec.js
. Notice the .spec.js
in it's name. This is a pattern and you will understand later what is used for.
So, import our own module to the test file:
'use strict';
import RssFeedEmitter from '../../src/rss-feed-emitter.js';
Now let's import Chai and use it's expect
assertion function:
'use strict';
import RssFeedEmitter from '../../src/rss-feed-emitter.js';
import chai from 'chai';
let expect = chai.expect;
And we are ready to test the most basic thing: if we create and instance from our module, does it return an object as expected? Let's write a test for this scenario:
'use strict';
import RssFeedEmitter from '../../src/rss-feed-emitter.js';
import chai from 'chai';
let expect = chai.expect;
describe( 'RssFeedEmitter ( unit )', () => {
describe( 'when instantiated', () => {
let feeder = new RssFeedEmitter();
it( 'should return an Object', () => {
expect( feeder ).to.be.an( 'object' );
} );
} );
} );
So we expect that the instance feeder
is an object
. How can we run this spec to see the results?
Running tests
Since we wrote the source code and test in ES6, we need to tell Mocha to use a compiler (Babel) and you do this by passing some arguments to it:
We are going to run this a lot of times so it's better to create a npm script
to easy access this command.
Edit your package.json
and add a new line in the scripts
session:
{
"name": "repository-demo-github",
"version": "0.0.1",
"description": "This is a demonstration repository",
"main": "index.js",
"scripts": {
"test-unit": "mocha --compilers js:babel-core/register test/unit/**/*.spec.js"
},
//...
See what we did there? Now, everytime you run this in your command line:
$ npm run test-unit
Npm will run mocha --compilers js:babel-core/register test/unit/**/*.spec.js
Let me explain this command:
mocha
Binary that read and runs the tests.--compilers js:babel-core/register
Register Babel as a compilertest/unit/**/*.spec.js
The pattern Mocha will search for files. See the*.spec.js
? We can now add other files inside the test directory and if they don't match the pattern, won't be executed as test specs.
Now, run the npm run test-unit
script and you will see something like this:
Amazing! Let's write the rest of the assertions to ensure all public interfaces are there, for example, we expect that add
method will be a function, right?
'use strict';
import RssFeedEmitter from '../../src/rss-feed-emitter.js';
import chai from 'chai';
let expect = chai.expect;
describe( 'RssFeedEmitter ( unit )', () => {
describe( 'when instantiated', () => {
let feeder = new RssFeedEmitter();
it( 'should return an Object', () => {
expect( feeder ).to.be.an( 'object' );
} );
} );
describe( '#add', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.add ).to.be.a( 'function' );
} );
} );
} );
Results in:
Let's add all public methods:
'use strict';
import RssFeedEmitter from '../../src/rss-feed-emitter.js';
import chai from 'chai';
let expect = chai.expect;
describe( 'RssFeedEmitter ( unit )', () => {
describe( 'when instantiated', () => {
let feeder = new RssFeedEmitter();
it( 'should return an Object', () => {
expect( feeder ).to.be.an( 'object' );
} );
} );
describe( '#add', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.add ).to.be.a( 'function' );
} );
} );
describe( '#emit', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.emit ).to.be.a( 'function' );
} );
} );
describe( '#on', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.on ).to.be.a( 'function' );
} );
} );
describe( '#list', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.list ).to.be.a( 'function' );
} );
} );
describe( '#remove', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.remove ).to.be.a( 'function' );
} );
} );
describe( '#destroy', () => {
let feeder = new RssFeedEmitter();
it( 'should be a Function', () => {
expect( feeder.remove ).to.be.a( 'function' );
} );
} );
} );
Results in:
Next step
coool