Writing maintainable integration tests for web applications

I guess I need to supply some context here: I’m still in the JavaScript world and I’m still writing desktop-like applications that run in the browser. I only load the DOM once. Here we go:

Every test you add to your application creates a dependency on it. More tests mean more dependencies. Dependencies spell trouble, especially if you depend on code that changes a lot, a.k.a. unstable components.

If you have a test to verify the correctness of a feature, the test should touch a minimal amount code, and it should ideally only touch stable components.

A common problem with integration tests is that they break for reasons having nothing to do with the feature they are testing. You often run in to this problem if you are testing thru the UI. The UI is very unstable (it changes a lot). Minor design changes can break tests. If you cannot easily change your application without creating extra work, the ROI of the integration tests is diminishing.

One solution is to ignore the outer layer of the UI and instead test one layer in. When I write desktop-like web applications I have a thin view layer that encapsulates all the UI interaction (http://bjarte.com/post/effective-javascript-unit-testing). This means that I can invoke every user action thru the view layer.

Let’s look at the following example of a search box:

search

The view would look something like this:

function SearchView(callback) {
  
  $("#search").click(function () {
    callback($("#q").val());
  });

  function doSearch(){
    $("#search").click();
  }

  return {
    doSearch: doSearch
  }
}

Somewhere else in my code I will make all my views visible globally thru a “views” collection. From my tests I can now invoke behaviour by talking directly to the SearchView:

views.searchView.doSearch(); 

I actually use WatiN to test thru the browser. The only line of code I need in my test (actually specification) to invoke the behaviour is

Browser.Eval("views.searchView.doSearch();");

As you can see, some of my application code is there only to support integration tests (e.g. the doSearch method on the view). I don’t have  a problem with that.You can plug a computer into a modern car to diagnose it. Why shouldn’t you be able to diagnose software?

The point here is that my tests depend on more stable code. The layout can change. The button can move, or perhaps become an image. The search behaviour will stay the same. Hopefully.

Obviously you are not testing EVERYTHING when you don’t run the tests thru every layer of the application. But you know what ? You cannot test everything anyways.  You come to a point where writing more tests will not give you more benefits. At some point more tests become a problem, a maintenance problem. Where you draw this line is dependent, not only on your technical challenges, but also the people in your team, the culture, the process and many other factors. Context, context, context.

Later.

Comments F Share

Effective JavaScript unit testing

Most JavaScript testing frameworks run in the browser and are tightly coupled to the DOM.

I don’t care about the DOM and I definitely don’t care about the browser, at least not when I am (unit) testing my JavaScript components.

This probably needs some context; I’m not writing web sites with 5 lines of JavaScript in them you see.  I’m writing desktop like applications that run in the browser. This means I have a lot of widgets and screens that need to talk to each other. I am also doing XMLHTTP calls to the server. All the interaction needs to be tested.

I don’t want to run the tests thru the GUI. It’s to brittle. Changing an a-tag to an input-tag or moving a component on the page can easily break a test. Testing is supposed to improve productivity, not slow it down.

I use the Model-View-Presenter design pattern to design my application layer. This means I have a thin layer, call “the view”,  over my HTML that abstracts away both the DOM and with it, the browser.

The View

Let’s say I have the following component in my application. (It would probably say “search” and not “Google search”, but you get it)

image

The corresponding HTML would look something like this (ignoring the lucky-button)

<input id="q" type="text" />
<input id="search" type="button" />

I would now create a SearchView module to put an abstraction on top of this HTML (using some JQuery magic)

function SearchView(callback){
	$("#search").click(function(){
		callback($("#q").val());
	});
}

Now the rest of my code will depend on the SearchView function, and only the SearchView function will depend on the browser DOM. But that’s no problem. We can always create a fake SearchView function to act as a stand in for testing purposes.

The key here is that even if I build a very complex application with a lot of interaction, it is only the thin view layer that is depending on the browser DOM. The rest of the code is pure JavaScript.

Testing the code (on the Windows platform)

So I have A LOT of JavaScript code to test, and it does not depend on the browser DOM, so why would I need a browser to test the code ? Wouldn’t it be much better to run the tests thru a command line JavaScript interpreter? Or even better, have the tests run inside Visual Studio ? I definitely think so. Opening up a browser to run a unit  test is way too much friction for me.

There is a JavaScript interpreter build into Windows. You can run it thru the cscript command line tool. To run a file, you do the following:

cscript myFile.js

Obviously if you are doing any meaningful testing you need to load multiple files into the environment, the testing framework, the tests, and the system under test. Luckily you can run multiple files at the same time by creating an xml file. Let's call the file test.wsf.

<?xml version="1.0" encoding="utf-8" ?>
<package>
   <job id="1">
     <script language="JScript" src="TestGui.js" />
     <script language="JScript" src="TestRunner.js" />
     <script language="JScript" src="Foo.js" />
     <script language="JScript" src="FooTests.js" />
   </job>
</package>

You can now run all the files

cscript test.wsf

We can now use this command line tool inside Visual Studio by creating an “external tool”

Tools -> External tools

image

By adding a shortcut to the external tool, I can run my JavaScript tests from anywhere in the Solution, only using a single keystroke. AND IT’S FAST!

The test runner / framework

As I mentioned previously, most JavaScript testing frameworks out there are tightly coupled to the browser DOM. That will not fly when you are using the Windows Script Host. I chose to build my own little test framework to run the tests. It is very small, and only have three method calls that are coupled to the environment it is running in.

//write to console
WScript.Echo(s); 	
...	
//quit application with error (which will break the build on TeamCity)
WScript.Application.Quit(1);	
...
//write to StdErr
WScript.StdErr.WriteLine(s);    

As you might tell from the code sample above, I run these tests on our CI server as well. No problem there.

My home-made testing framework is in an early stage. You can look at it if you want to, but don’t expect too much: http://github.com/BjartN/BigUnit.

Well, that’s it for now.  Later.

Comments F Share

Object design in JavaScript

JavaScript has gotten a bad reputation in the software industry. Most of it is related to the browser DOM and incompatibility across browsers. This problem is starting to go away due to great frameworks like Jquery and Prototype. Web 2.0 sites with heavy AJAX functionality forces browser manufacturers to improve their JavaScript interpreters. JavaScript is even becoming a contender on the server side.

Designing objects

If you google ”object oriented design (OOD) using JavaScript” you will find that most people build JavaScript objects using prototype and the “new” keyword. Here is how you normally would create an object:

var Address = function (street) {
  this._street = street;
};

Address.prototype = {
  setStreet: function (street) {
    this._street = street
  },

  getStreet: function(){
    return this._street;
  }
}

I create the function Address. This function will work as my constructor. Then I extend Address’ prototype with two functions, setStreet and getStreet. I can now use the “new” keyword to create an address object with the two functions “setStreet” and “getStreet” baked in

var addr = new Address("Elm Street");

If I want to, I can change the street name in the address object

addr.setStreet("Old Berry Vale");

This is all good. However, there are some problems with this approach.

This and that

If you come from OO languages like C# or Java, you are tempted to believe that the “this” keyword refers to the current instance of the Address class. However that’s not always true. The this” keyword actually refers to the context in which the function is invoked. If somebody for some reason invokes the setStreet function in a different contex you will get into trouble. This usually happens when we pass around function pointers. I can use the "call" function on the "setStreet" function to illustrate this by calling the function "setStreet" in the context of an empty object ({})

addr.setStreet("Old Berry Vale"); 
areEqual("Old Berry Vale", addr.getStreet()); //nothing strange here

addr.setStreet.call({}, "Cotton Acres"); //calling method from different context
areEqual("Old Berry Vale", addr.getStreet());  //hey.. the name didn't change
Are you protecting your privates ?

Well, are you?

addr._street = "Pleasant Island Stead"; //I can change internal state
areEqual("Pleasant Island Stead", addr.getStreet()); 

Ai ai ai. The “_street” instance variable isn't really private. Not having private instance variable when you create objects like this is problematic.

Closures. The road to a better approach.

From the description above you might believe that JavaScript is troublesome. However, as with any sharp tool, you need to use it right if you don’t want to get hurt.

JavaScript has the fine notion of closures. And yes, now it’s time to concentrate:

function main(foo) {

  runFunction(sayHello);

  function sayHello() {
    alert(foo);
  }
}

function runFunction(callback) {
  callback();
}

main("Hello world"); //=> “Hello world”

In JavaScript you can define functions within functions. This might seem a little bit strange, but you get used to it. The ”runFunction” is straight forward. It takes a function pointer as an argument, and executes that function . The “main” function is more fun, but still pretty simple. It just passes the “sayHello” function to the “runFunction” function.

The interesting thing here is that when the “runFunction” invokes the “sayHello” function, the sayHello function knows the value of “foo”. How can this be? The answer is that even after you pass the “sayHello” function it still has access to the parent scope where it was defined. The “sayHello” function is a closure. Cool huh ?

Another thing to mention here is that the “sayHello” function is private within the “main” function.

A better approach

By using closures and a couple of additional tricks you can create “objects” that doesn’t have the problems outlined in the previous solution. This is how you do it:

var Address = function (street) {

  function setStreet(s) {
    street = s;
  }

  function getStreet() {
    return street;
  }

  //explicitly make private methods public
  return {
    getStreet:getStreet,
    setStreet:setStreet
  };

}

You can now create an “instance” of the “object” this way:

var addr = Address("Elm Street");

Notice we are not using the “new” keyword, and we are not using “prototype”.  We are basically calling the Address function which returns an object containing the getStreet and the setStreet function. The “street” variable acts as an instance variable. The function getStreet and setStreet has access to this variable since they are closures.

The setStreet and getStreet functions are initially private so we need to return them in an object to make them public. The act of making functions public is explicit, which I think is a good thing.

We get the expected behaviour:

var addr = Address("Elm Street");
addr.setStreet("Old Berry Vale");
areEqual("Old Berry Vale", addr.getStreet());

addr.setStreet.call({}, "Cotton Acres"); //different context doesn't create problems
areEqual("Cotton Acres", addr.getStreet());

addr.street = "Pleasant Island Stead"; //private variables cannot be tampered with
areEqual("Cotton Acres", addr.getStreet());
 

Good good. One other thing to notice is that the code is now visually much cleaner. Well, that’s it for now.  [UPDATE] Look at the “yahoo javascript module pattern” if you want to learn more [/UPDATE]

A small note on methods and functions

In mathematics a function always returns the same value on the same input. In this post I have used the word in a more loose fashion because the of the “function” keyword in JavaScript. Methods and functions are not the same. Just so you know :)

Comments F Share