Wednesday, November 29th, 2006

TDD and Javascript with JsMock

Category: JavaScript, Testing

>I’ve been using JsUnit for a while now to do Test Driven Development with OO Javascript. I’ve been implementing mock objects simply by stubbing out methods and adding in a limited amount of logic, but it’s just not the same. So, this past weekend was the time to come up with a port of jMock to Javascript. But before reinventing the wheel, I thought I’d take a look around one more time to see if anyone had beaten me to the punch. Enter JsMock, a Javascript mock objects library that supports Firefox 1.0+, IE6+ and Safari 1.5+.

You can add JsMock into JsUnit tests simply by including the jsmock.js file into your unit test HTML page and adding some mock object code to your tests. An example:

javascript
< view plain text >
  1. var mockControl = null;
  2. var div = null;
  3. function setUp()
  4. {
  5.  mockControl = new MockControl();
  6.  div = document.createElement("div");
  7. }
  8.  
  9. /* Interface we will mock */
  10. function DocWrapper() {};
  11. DocWrapper.prototype = {
  12.  byId:function(){},
  13.  create:function(){},
  14.  appendToBody:function(){}
  15. };
  16.  
  17. /* Object we will test */
  18. function Hello(docWrapper) { this.docWrapper = docWrapper; };
  19. Hello.prototype = {
  20.  displayHello:function(id) {
  21.   var elem = this.docWrapper.byId(id);
  22.   if (elem == null) {
  23.    elem = this.docWrapper.create("div");
  24.    elem.id = id;
  25.    this.docWrapper.appendToBody(elem);
  26.   }
  27.   elem.style.fontWeight = 'bold';
  28.  }
  29. };
  30.  
  31. /* tests we will run */
  32. function test_NewElem() {
  33.  var mock = mockControl.createMock(DocWrapper);
  34.  mock.expect().byId("helloContent").andReturn(null);
  35.  mock.expect().create("div").andReturn(div);
  36.  mock.expect().appendToBody(div);
  37.  
  38.  var hello = new Hello(mock);
  39.  hello.displayHello("helloContent");
  40.  
  41.  try {
  42.   mockControl.verify();
  43.  }
  44.  catch(e)
  45.  {
  46.   fail("Verify should have passed: " + e);
  47.  }
  48. }
  49.  
  50. function test_ExistingElem() {
  51.  var mock = mockControl.createMock(DocWrapper);
  52.  mock.expect().byId("helloContent").andReturn(div);
  53.  
  54.  var hello = new Hello(mock);
  55.  hello.displayHello("helloContent");
  56.  
  57.  try {
  58.   mockControl.verify();
  59.  }
  60.  catch(e)
  61.  {
  62.   fail("Verify should have passed: " + e);
  63.  }
  64. }
  65.  
  66. function test_BadOrder() {
  67.  var mock = mockControl.createMock(DocWrapper);
  68.  mock.expect().create("div").andReturn(div);
  69.  mock.expect().byId("helloContent").andReturn(null);
  70.  mock.expect().appendToBody(div);
  71.  
  72.  var hello = new Hello(mock);
  73.  hello.displayHello("helloContent");
  74.  
  75.  try {
  76.   mockControl.verify();
  77.  }
  78.  catch(e)
  79.  {
  80.   fail("This will fail: \n" + e);
  81.  }
  82. }

In the above example, we stub out an interface for a wrapper for the document object (in Firefox and Safari you can actually mock the document object, but not in IE), mock it out for different scenarios, then put the Hello class through its paces, first when there is no DOM node with id “helloContent” and next when there is one. We don’t actually modify the DOM in this case, we just reuse a scratch DIV node that we create in the setup. The last test fails on purpose, just to illustrate how the order of calls matters in JsMock.

:jsmock.JPG

The documentation is a little sparse, so you have to work your way through the examples to get the gist of JsMock. Prior knowledge of jMock or EasyMock is definitely helpful. If you never do any OO Javascript or TDD, you won’t understand why you need something like JsMock. If you do TDD, have at it. It’s just another step in the professionalization of Javascript development.

BTW, this tool was just released in August and updated in the last few days, so the paint is still wet on it. Please consider making bug reports to the authors.

Posted by Dietrich Kappe at 11:21 am
2 Comments

++++-
4 rating from 20 votes

2 Comments »

Comments feed TrackBack URI

Oh cool! Thanks for sharing this. I’ve found the combination of TestNG and EasyMock to be indispensable in my toolset for testing non javascript related functions. It will be interesting to see what a javascript equivalent construct allows.

Comment by Jesse Kuhnert — November 29, 2006

[...] Ajaxian » TDD and Javascript with JsMock (tags: javascript test unit-test ajaxian) [...]

Pingback by links for 2006-12-01 « Benx Blog — December 1, 2006

Leave a comment

You must be logged in to post a comment.