Writing unit testable JavaScript code

11 Dec

Today’s web applications heavily use JavaScript to enrich their User Interface. As we rely on JavaScript to accomplish more and more demanding features, it becomes necessary to apply engineering practices to JavaScript and consider it as a legitimate programming language.

I recently blogged about a JavaScript testing framework called JsTestDriver. But it would be useless if I cannot write JavaScript code that is unit testable to leverage my testing framework. A benefit of writing unit testable code is that it will also help you to write maintainable code.

Before going any further, I would like to briefly set a common ground on those 2 notions.

Unit testing

There are several kind of testing that can be performed to ensure a product’s quality:

  • Unit testing: test the smallest unit of your code. The goal is to ensure that all methods of your objects works correctly, independently from other objects. There are many unit test framework available such as QUnit, JsTestDriver that I highly recommand.
  • Integration testing: test the interaction/integration between your objects. Selenium is a popular integration testing tool.
  • Functional testing: test your use cases which could be a serie of steps executed by the user.

Writing unit testing will:

  • allow you to verify if a code change breaks or not you code.
  • improve the quality of your code. A good practice is to write your code first. It can be strange at first but it will force you to break your implementation into small, independent chunks of code that serve 1 goal. Because your code is broken down, it is easier to see duplicate code, clearer to understand the purpose of each method.
  • because you broke down your code in small pieces, the method should be as simple as it gets and therefore be self documenting

As you can see, I did not say that your application will be bug free. Why not? First of all, software specifications can be incomplete or incorrect. You could be missing certain use cases. Secondly, unit testing ensures that your objects work correctly but outside of the application context, independently from other objects. For more on unit testing in JavaScript, please refer to Nicholas C. Zakas’s video on test driven development.

As a note, it is important when writing unit tests to keep in mind the goals to be achieved, i.e writing tests against unit of your code. Writing bad unit tests can be costly to maintain because you’ll end writing and maintaining unit tests with low value. See the very interesting post Writing Unit Test: Best and Worse Practices for more information on that topic.

Maintainable code

What is maintainable code? Maintainable code is code that is:

  • Understandable
  • Intuitive
  • Adaptable
  • Extendable
  • Debuggable/Testable

If you would like to learn more information on writing maintainable JavaScript code, please refer to this excellent video from Nicholas Zakas – Maintainable JavaScript.

In his video, N. Zakas lists several elements that will help you to write maintainable code such as code convention, separation of concerns, coding practices … In today’s post, I just want to briefly talk about writing testable code.

Let’s get started

For the context, we will imagine we want to implement a calculator with 2 input fields and 2 buttons to perform basic operations (+ and -) and a label to display the result. How would you write testable JavaScript code for such as feature? It can seem strange since it is bound to the UI. In other programming languages such as Java, C#, PHP, Ruby … you are dealing with objects and testing their methods. Well, let’s do the same!

There are many ways to achieve today’s goal but they all converge towards the same idea. You first need to visualize this feature as a module. This module has a state (values of the inputs), operations and event handlers bound to the buttons.

I am going to write the code first and explain afterwards:

var calculator = {
	value_1:0,
	value_2:0,
	config: {
		labelSelector:"#resultLabel"
	},
	/* Add event handlers to the buttons */
	init:function(){
		$("#add_button").bind("click", function(){
			this.value_1 = $("#input1").val();
			this.value_2 = $("#input2").val();
			this.add();
		});
		$("#substract_button").bind("click", function(){
			this.value_1 = $("#input1").val();
			this.value_2 = $("#input2").val();
			this.substract();
		});
	},

	/* Some comments for the add function */
	add:function(){
		var result = this.value_1 + this.value_2;
		this.displayResult(result);
	},

	/* Some comments for the substract function */
	substract(){
		var result = this.value_1 - this.value_2;
		this.displayResult(result);
	},

	/* Some comments for the display function */
	displayResult:function(value){
		$(this.config.labelSelector).text(value);
	}
};

Explanations

  1. I created an object (in this case, an object literal) that encapsulates my properties and my methods.
  2. When the DOM is ready, we will initialize the object as follow: calcultator.init();. The init() method attaches the event handlers to the buttons. It is a nice approach because by reading the init() method, I know what the module is going to do without having to look at the implementation details.
  3. We implement the functions called in the event handlers. This is a good approach because we do not mix event handlers and business logic. Say we want to change the event on which we perform an ‘add’, we just need to change the trigger event but we can leave the add method untouched.
  4. Even if this is a simple example, I kept in mind the idea of keeping the method to serve 1 testable purpose. When writing unit tests, I can easily call my add method and test it against an expected value.
  5. I created a displayResult that is being called in both my add and substract mehotds so I can test it and I do not repeat the display logic in the add nor the substract method.

Thoughts

Did we write maintainable code?

  • Understandable: the logic is separated in small units of code making it easy understand and we commented each functions.
  • Intuitive: the init method explains quickly what the module does
  • Adaptable: if needed, we can easily change the triggering events of the add or the substract method actions
  • Extendable: if is easy to add a new feature such as multiply or divide by adding a new event handler and a new function
  • Debuggable/Testable: code is splitted in unit testable code

Of course, it is a very simplistic example and I do not drill down into details. For example, to improve the code above, you will still have to write:

  1. exception handling
  2. comment (unintuitive) code
  3. write your unit tests

The list of possible improvement is far beyond the scope of this post. What I wanted to share is the pattern to use when writing modular JavaScript:

  • encapsulating you module’s behavior in a object
  • using an init() method
  • separating event handling from business logic
  • I am obviously using jQuery library. My recommendation is to avoid as much as possible to refer to CSS selectors in your functions. You can put them in a config object property like I did for the label selector. It is up to you. The advantage is that is you decide to change your markup, your changes in your JS code will be minimal.

Last but not least, run your tests on all browsers. Even if you use a library that is cross browser libraries such as jQuery to implement events … there are still differences in the behavior of browsers when it comes to run JS code (and differences of performance as well!).

I hope you enjoyed this post and that it gave you some ideas on how to write testable and maintainable code!

Thanks for reading.

About these ads

2 Responses to “Writing unit testable JavaScript code”

  1. Andy March 16, 2010 at 3:24 pm #

    I strongly encourage you to write a test for your Calculator class that demonstrates your bullet points in runnable fashion. There are far too many blog posts with simplistic examples, or articles like this that say the code is testable, but don’t prove it. You are off to a good start here, but given your high ranking for “writing testable javascript” in google, I suggest you provide test code in JsTestDriver, QUnit, or whatever.

    • ruemarin March 16, 2010 at 4:58 pm #

      Thanks for the encouragement, I definitively see your point. I’ll improve this post with some test and a better formatting. Please, don’t hesitate to make any other suggestions, they are welcome!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: