As frontend developers, we have the responsibility of ensuring that our code works. Often times, this comes down to large test suites that, even when automated, take precious time away from our first love—writing code. In an effort to keep the spirit of tested, solid code, we can speed up the process by splitting our tests into two types: unit tests and integration tests.
Unit Tests
Unit tests can best be described as a way to break your code down to the smallest piece and ensure that it behaves in an expected manner. This means that you will have a large number of highly specific tests for small cross sections of your code. Unit tests should be written so that they only require mocked data and services instead of realtime data or databases.
These tests are written this way in order to preserve test data and ensure that the data being used is not corrupt nor unavailable during testing. If you do not write your unit tests this way, you are likely to get false passes, failures, timeouts, and create a speed bottleneck in your test suite.
One of the biggest mistakes we can make in creating unit tests is formulating them to depend on DOM objects and tying them into an event structure. In doing so, we will pigeonhole ourselves into depending on setTimeout’s, waitFor’s, and a loss of precious development time.
If you ever find yourself writing tests that are tied to the DOM and interactions with UI elements, you’re writing integration tests.
Integration Tests
Much like unit tests, integration tests ensure that small parts of our code work in the way that they are intended. However, the key difference in these two types of tests is that integration tests are meant to test application interaction and UI modifications. Because of their dependance on DOM interaction, these tests can be slow and take up the majority of the time your test suite runs.
One way in which you can speed up your integration tests is by using headless browsers such as PhantomJS. Headless browsers are simply browsers that give the full functionality and capability of a normal browser, but without the overhead cost of a graphical interface. Without the extra weight, headless browsers can run our tests faster and with the same precision as your normal development browser (Chrome, Firefox, Safari, etc).
With our test suite having both unit tests and integration tests, we need a way to run them separately to try and cut down on the time it takes our tests to run. However, we can do better.
Phantom + Jasmine = Gulp
Recently, I wrote a Gulp plugin to help us speed up slow test suites. Gulp is a Node build system that uses memory to run tasks asynchronously. Using Gulp will allow us to run both unit tests, and integration tests, both separately and asynchronously to get the fastest run out of our test suite.
This plugin also allows you to run separate tasks in Gulp and take advantage of its features to get a huge speed boost. In order to ensure speed, by default, the plugin runs whatever tests are piped in, through Node and not a headless browser. I built this on purpose to keep myself honest about how I write my tests and ensure that I keep my unit tests clear of DOM interactions and accidently make them start to look and feel like integration tests.
While using the plugin, you can also conditionally choose to run your tests with a headless browser by setting the option {integration: true}
in your Gulp task:
var gulp = require('gulp');
var jasmine = require('gulp-jasmine-phantom');
gulp.task('default', function() {
return gulp.src('spec/test.js')
.pipe(jasmine({
integration: true
}));
});
This option can be used in order to run any test(s) through PhantomJS; however, like I said before, it is called “integration” in an effort to keep us honest about how we write our tests.
To get to our end goal of having Gulp run our unit tests and integration tests asynchronously, we only have to specify two tasks as follows:
var gulp = require('gulp');
var jasmine = require('gulp-jasmine-phantom');
gulp.task('unitTests', function () {
return gulp.src('spec/test.js')
.pipe(jasmine());
});
gulp.task('integrationTests', function() {
return gulp.src('spec/test.js')
.pipe(jasmine({
integration: true
}));
});
Then, all we have to do is run gulp unitTests
& gulp integrationTests
, and we have succeeded!
In the end, our biggest opponent in writing fast test suites is ourselves. Even with fast tools, such as Gulp, we can still slow our test suites if we are not making a conscious effort to separate them into unit tests and integration tests.
If you decide to use the plugin, please give me feature requests, and if you feel so noble, a pull request as well!
Want to Learn More?
We have a brand new Build Right workshop debuting in 2015 all about Frontend Testing designed to give developers the tools and techniques to ensure your code stands strong. Your first two chances to catch it will be at CodeMash in January and at SXSW in March.