Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Continuous JavaScript TDD with NodeJS and Gulp

See in this article how to do TDD with much more efficiency and productivity using NodeJS and Gulp front-end frameworks

Those who practice TDD in their day to day know the benefits of cleaner, tested and easy to modify code. These benefits, however, do not come automatically, because it takes a lot of study and practice to fully understand the technique and how to apply them.

Consider the recommendation to take short steps, ie, test the code gradually. The big advantage is that when a problem occurs, we know immediately the exact spot of the event. However, very small steps may bother the programmer. You have to interrupt your thought flow at all times to change window, give the command to run the tests, see the result and only then resume the thread. Often what happens is that it fails to follow the recommendation, giving up the benefits.

Is the problem with the developer or with the development environment? In this article you will learn a way of practicing TDD in JavaScript that streamlines the results visualization and promotes continuity in the workflow. You only need to save the edited file to see test results immediately.

TDD Continuous: Responsiveness

Practicing Continuous TDD means that you will see the result of your project tests running without leaving the development environment and executing a specific command. The command will run automatically as soon as you save the file you're editing. Set up your environment using the tools described in this article and notice the difference in your productivity.

  • Node.js is a JavaScript runtime environment that runs directly on the operating system, usually in servers. It allows you to run JavaScript code outside the browser, expanding the scope of the language.
  • NPM (Node Package Manager) facilitates the download and installation of libraries and third-party tools. It is similar to NuGet (.NET), Maven (Java) and RubyGems (Ruby).
  • Jasmine is a framework for running automated tests that can be used in any JavaScript environment, whether inside or outside the browser. It allows specifying the expected behavior of a system in the same manner as rspec tool (ruby).
  • Gulp is a project build automation tool, like Make (C), Ant and Maven (Java) and Rake (Ruby). Gulp allow us to write scripts to perform common tasks in the JavaScript world like obfuscate and minify files, convert SASS/LESS to CSS and convert CoffeeScript to JavaScript. In the context of Continuous TDD, Gulp is useful to observe the filesystem and trigger the execution of the tests when there are changes to existing files.
  • gulp-jasmine is a plugin that allows you to start Jasmine from Gulp. Generally, Jasmine is used in conjunction with the browser and, in this article, it will run on Node in a terminal window.
  • Browserify is a module manager for JavaScript in the browser that lets you use the same standard definition and export modules adopted by the Node. This makes it possible to run in the browser, the code originally written for the Node, without any modification.

Example 1: Creating a project from scratch

In this section we will be set up a JavaScript project from scratch that will demonstrate the configuration of the tools used to practice ContinuousTDD.

Let's start by opening a terminal window and running the commands described to install Node.js and NPM. In Ubuntu or derivatives, use the following code:

 sudo apt-get install nodejs-legacy
 # if nodejs-legacy won't be available, switch for nodejs
sudo apt-get install npm

On other operating systems, visit the Node page (see Links section), download and install the appropriate version. NPM will be installed along with Node.

To verify that the installation was successful, run the following commands and make sure the numbers of the installed versions appear:

node -v
npm -

To install Gulp globally, use the following command:

sudo npm install gulp -g

If you are in Windows, omit the word sudo. This command lets you run gulp command from any directory.

Now we need to create a directory called example1 for the new project and access it. In any operating system, use the following commands for this:

mkdir example1 cd example1

Then, start a new project using NPM through the following command:

npm init

This command creates a package.json file, which is similar to Maven pom.xml (Java). It describes the basic data of your project and also the dependencies of external packages.

You will be asked to fill out various data, such as project name, version, description and license. For the purpose of this article it is not necessary to fill any of such data. You can simply press Enter on all the questions to use all default values.

Install gulp and gulp-jasmine packages locally using the following command:

npm install gulp gulp-jasmine --save-dev

This installs the gulp and gulp-jasmine tools locally, ie, only in the current project in a directory called node_modules. The --save-dev part instructs npm package.json to update the file, adding gulp and gulp-jasmine as project dependencies in development time. This lets you download and install the dependencies again at any time in the future just running npm install command. This is useful if you don't want to add dependencies to version control. If you use Git, for example, you can add node_modules to .gitignore file, avoiding versioning external dependencies.

It must create a Gulp configuration file in the project root. To do this, create the src folder with the following command sequence:

mkdir src 
cd src 
mkdir spec 
mkdir prod 
cd ..

Creation of gulpfile

The file that sets up the execution of Gulp is called gulpfile. Therefore in the project root, create a gulpfile.js file with the content shown in Listing 1.

Listing 1. Contents of example1/gulpfile.js

var gulp = require('gulp');
var jasmine = require('gulp-jasmine');


var srcPath = 'src/**/*.js';


gulp.task('test', function() {
		  gulp.src(srcPath)
					  .pipe(jasmine());
});


gulp.task('continuous-tdd', ['test'], function() {
		  gulp.watch(srcPath, ['test']);
});


process.on('uncaughtException', function(e) {
		  console.error(e.stack);
});

This file defines two tasks to gulp:

  • test: this task performs the tests once and ends;
  • continuous-tdd: this task runs the tests once and then looks at the file system and re-run the tests automatically every modification. The process.on('uncaughtException')stretch instructs Node.js to, rather than terminate the program in the event of exceptions, just write them on the screen. This is useful to keep Gulp running even in case of compilation errors. This solution is acceptable in this case because Node is being used only as an auxiliary tool of development. To host an application on Node production, this solution should not be used.

Source code of the project

After you create the project structure, the JavaScript files will be written. For this example, imagine a class representing a tree, which should offer five fruits. First, it is writing a specification for trees. Then the Tree class will be implemented. This will be done in very short steps, with continuous checking to see if the code is correct. In a dynamic language and interpreted as JavaScript, it makes a big difference: you do not have a compiler available to point out many programming errors, such as in Java or C#. Thus, automated testing becomes the detector of these errors.

The specification code (i.e., test) is placed in src/spec and production code (ie, one that implements functionality) in src/prod. Open a text editor and create the TreeSpec.js and Tree.js files, present in Listings 2 and 3, respectively.

Listing 2. Contents of example1/src/spec/TreeSpec.js

var Tree = require('../prod/Tree');

describe('Tree', function() {
	it('must have 5 fruits', function() {
		expect(new Tree().getFruits().length).toBe(5);
	});
});

Listing 3. File contents of example1/src/prod/Tree.js

function Tree() {
  } 
  module.exports = Tree;

TreeSpec.js file contains the specification of the Tree class, while Tree.js file defines a Tree class, even without any property or method. The last line containing the module.exportstells to Node.js that moduleexports the Tree class. In a Node project, each JavaScript file is a module and each module must export to others what it wants to become visible. In our case, Tree.js file exports the Tree class and the TreeSpec.js file, when make the call to require('../prod/Tree'), gets the Tree class.

Implementation of Gulp

Now, there is a specification for the Tree class and an outline of its implementation. In a terminal, in the root directory of the project, run this command:

 gulp continuous-tdd

The only existing test in the project will be executed and the result should be:

TypeError: Object #<Tree> has no method 'getFruits'

Gulp will keep running, waiting for changes in the file system to run the tests again.

Next step is to implement getFruits() method in Tree class. The ultimate goal is for the tree builder to create a fruit vector and store it as a property of the object.

Continuous TDD in action

Practicing Continuous TDDimplies in simultaneously view the code and the tests. For this, let's make visible our text editor and terminal windows, one beside the other. If you are on Windows or Linux Mint, you can do this as follows: click on the editor window and press Windows Key + Left Arrow; click on the terminal window and press Windows Key + Right Arrow. Windows are arranged side-by-side in a convenient way.

ModifyTree.js file to be like it's shown in the Listing 4.

Listing 4. Tree.js code after first modification

function Tree() {
}


Tree.prototype.getFruits = function() {
	return new Array(5);
};
module.exports = Tree;

When you save the file in a text editor, look at the terminal that the test is performed automatically, now with success. You should see the message "spec 1, 0 failures".

Thinking about TDD, just use fake implementation, because the method is not yet a full work: it just creates a new temporary array and returns it. The test passes, but there is still storing the vector in a property of the object. Let's turn this into a real fake implementation.

Complete the builder of the Tree class with this line of code and save the file:

this._fruits = new Array(5);

The test should be run again and will continue being successful. Change the line return new Array (5);by this and save the file:

return this.fruits;

The test should now fail because it is missing the character '_' before the word fruits. Correct the error by switching tothis._fruits, save the file and see the test passes again.

Note the ease to realize the typo at the exact time and place in which it occurred. This allows us to work on the project continuously evaluating the result of each modification.

Example 2: adaptation of a web project

Now we will see how to adapt a web project using Jasmine to run on Node.

An important difference between Node and the browser is the module management mechanism. In Node a valueis assignedto module.exports to export the contents of a module and we callrequire('./ my-module') to import it. What is assigned to module.exports is the only thing that is visible from outside the module. In web projects, export is usually done in the global scope and the import is made with the <script> in HTML pages. This has several problems:

  • Pollution of the global scope;
  • Dependencies between modules are implied;
  • Tendency to strong coupling;
  • Need to change the HTML to every module created, renamed, moved, or removed;
  • Inability to run the code in Node.js.

The solution to these problems is to adopt an efficient mechanism for module management. The newest version of JavaScript (ECMAScript 6) brings a native solution. While it is not feasible to adopt it for compatibility reasons, we can use one of many existing tools for that purpose. Among the best known are RequireJS, Almond and Browserify. The latter is what will be used in this article, mainly because of its simplicity of use.

Music player project

When Jasmine tool is downloaded from the official site (see Links section), the zip package includes a small sample project. This project simulates a player application of music. There are tests for the Player class (in PlayerSpec.js file) and there are two production classes (Player and Song). The structure of files and directories is shown in Listing 5.

Listing 5. Structure of files and directories Example 2

exemplo2/
	lib/
		jasmine-2.2.0/*
	spec/
		PlayerSpec.js
		SpecHelper.js
	src/
		Player.js
		Song.js
	MIT.LICENSE
	SpecRunner.html

SpecRunner.html is the page that loads modules and complete these checks. When you open this file in the browser, the tests run normally, as shown in Figure 1. However, if you try to run PlayerSpec module in Node, you'll see that the Player module has not been loaded. The design of the modules needs to be modified to be compatible with Node. For browser compatibility, you should use the Browserify.

Figure 2. Performance of tests in browser

The following commands will configure the sample project to run both in the browser and in Node, allowing practicing ContinuousTDDas in Example 1.

To install Browserify use a terminal and run:

sudo npm install -g browserify

If you are in Windows, omit the word sudo.

Download the zip of Jasmine from the address https://github.com/jasmine/jasmine/blob/master/dist/jasmine-standalone-2.2.0.zip?raw=true and extract it in a example2 directory. If you are using Linux, run in the terminal:

wget https://github.com/jasmine/jasmine/blob/master/dist/jasmine-standalone-2.2.0.zip?raw=true -O jasmine-standalone-2.2.0.zip 
unzip jasmine-standalone-2.2.0.zip -d exemplo2 
cd exemplo2

Change the source code to use the Node style modules management. Open src/Player.js in a text editor and add this line to the end of the same file:

module.exports = Player;

Do the same with src/Song.js. Add this line to the end of file

module.exports = Song;

In spec/PlayerSpec.js module, add these lines at the beginning of the file:

  Player var = require ('../src/Player');
  Song var = require ('../src/Song');

Create a bin directory in the root project, which will generate a single script containing all modules. Then, at the root of the project, run the browserify command. Still in the root directory of the project, run:

browserify spec/spec SpecHelper.js/PlayerSpec.js -o bin/browserify-bundle.js

Change SpecRunner.html to include the single script, so remove this excerpt:

  <! - Include source files here ... ->
  <script src="src/Player.js"> </ script>
  <script src="src/Song.js"> </ script>
   
  <! - Include spec files here ... ->
  <script src="spec/SpecHelper.js"> </ script>
  <script src="spec/PlayerSpec.js"> </ script>

and add this piece in place:

<script src="bin/browserify-bundle.js"> </ script>

Test the project in the browser, opening the SpecRunner.html page and that tests should normally occur.

Setting up and running Gulp

Now, to practice ContinuousTDDjust do as in the previous example. In the project root directory run the following command:

npm init #answer empty to all the questions
npm install gulp gulp-jasmine --save-dev

Create a gulpfile.js with the content shown in Listing 6.

Listing 6. Contents of example2/gulpfile.js

var gulp = require('gulp');
var jasmine = require('gulp-jasmine');

var srcPath = '**/*.js';
var specsPath = 'spec/*.js';

gulp.task('test', function() {
	gulp.src(specsPath).pipe(jasmine());
});

gulp.task('continuous-tdd', ['test'], function() {
	gulp.watch(srcPath, ['test']);
});

process.on('uncaughtException', function(e) {
	console.error(e.stack);});

After creating Gulpfile in the terminal, run in the project root:

gulp continuous-tdd 

With this, you should see the same result as the previous example: the terminal must show the tests and wait for changes in the file system to re-run them.

Conclusion

This article showed how to configure a JavaScript development environment to facilitate the practice of TDD. In addition to what was shown, some improvements are possible. First is the use of the gulp-watch outer package to detect the creation of new files (not only the modification of existing ones). You can also use the watchify package to call the Browserify automatically to every change, simplifying the frequency execution of the tests in the browser.

Links

Node.js: http://nodejs.org

Jasmine Framework: http://jasmine.github.io/

Gulp: http://gulpjs.com/

Gulp-Jasmine: https://www.npmjs.com/package/gulp-jasmine

Browserify: http://browserify.org/

Unhandled exceptions in Node.js: http://shapeshed.com/uncaught-exceptions-in-node

Gulp-Watch: https://www.npmjs.com/package/gulp-watch

Watchify: https://github.com/substack/watchify



Fabrí­cio Galdino is a software expert and has worked with IT analysis and business development for more than five years. It has extensive experience with testing, back and front-end technologies.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login