AJAX Travelogue (Part 6): Mocking in JavaScript

August 8, 2008

It’s been a while since I have written about AJAX development; I published Part  5 over two years ago. Why’s that, you ask? Well, at a given time I was either too busy actually doing AJAX stuff or – at other times – my focus had shifted away. It wasn’t before my talk about Test-Driven Ajax had been accepted for Agile 2008 that I finally took my time and rethought some of the things I had learned about the topic before.

Let’s set up the stage for part 6 of this show, which will deal with mocking in JavaScript. As a prerequisite I assume that you are using some kind of unit testing framework for JavaScript, like JsUnit or JsUnit (well, there exist two having this name) or – like I do – the framework coming with script.aculo.us.

Effective unit testing & especially test-driven development require that you test your units (think “functions” or “objects”) in isolation. That’s how stubbing & mocking come into the picture. Whereas mocking frameworks play a significant role in statically typed languages like Java or C#, some claim that dynamic languages don’t really need that kind of thing because the mere presence of closures and duck typing make mocking and stubbing by hand so easy. JavaScript has both – closures (aka functions) and duck typing, so let’s see how things turn out in a simple example. Consider the following two objects:

  var Speaker = {
    say: function(msg) {
      alert(msg);
    }
  };
  var DoubleSpeaker = {
    say: function(msg) {
      Speaker.say(msg+msg);
    }
  };

I would like to write a test for DoubleSpeaker.say to verify that Speaker.say is being called with the argument duobled. Since using the real Speaker object would result in an alert box, which is not suitable for an automated test, I have to find a way to substitute Speaker.say with some kind of mock function:

  testDoubleSpeaker: function() { with(this) {
    var actualMsg = null;
    var mockSay = function(msg) {
      actualMsg = msg;
    };
    Speaker.say = mockSay;
    DoubleSpeaker.say('oops');
    assertEqual('oopsoops', actualMsg);
  }}

This approach actually works, but it has a drawback. Since Speaker is a global object our test has changed the global state and other tests – those that want to use the real Speaker.say function – might fail because of our test. This sort of test interdependency is one of the biggest smells of unit testing, so we have to get rid of that stink and reset the global state on finishing:

  testDoubleSpeaker: function() { with(this) {
    var actualMsg = null;
    var mockSay = function(msg) {
      actualMsg = msg;
    };
    vor originalSay = Speaker.say;
    Speaker.say = mockSay;
    try {
      DoubleSpeaker.say('oops');
      assertEqual('oopsoops', actualMsg);
    } finally {
      Speaker.say = originalSay;
    }
  }}

To me that code looks an awfully lot like my very early mocking attempts with Java around 2001. The code is bloated and full of ceremony. The essence of the test could be written down in three lines:

  testDoubleSpeaker: function() { with(this) {
    makeAMockOf(Speaker.say);
    DoubleSpeaker.say('oops');
    checkThat(Speaker.say).wasInvokedWith('oopsoops');
  }}

I’ve intentionally chosen rather wordy lines to make it clear that this is not a real API – not that I’m aware of.

My personal take-away from even a simple example like the one above is two-fold:

  • Even a language like JavaScript can make good use of a framework to take the tedium away from mocking and stubbing.
  • Such a framework must be different than mock frameworks in other languages to compensate for the difference in programming idioms (e.g. the paramount use of global objects) and the fact that the basic building block in JavaScript is NOT the object but the function.

Luckily, you don’t have to write such a beast yourself, it is already out there… (to be continued)

Sleepless in Toronto

August 7, 2008

So, I’m here in Toronto at the Agile Conference. It is 4:31am now, which tells you that my body is still somewhat drawn between night and day. Never mind, though, that gives me time to write. Since this is my first visit to a conference in North America, I actually met – or at least saw – many of the people for the first time that I’ve known by email, by blog or by gossip for quite a few years. One fact that is being noticed “by the community” is the very low number of German participants and speakers. I’ve counted only five presentations from compatriots, that’s not much more that one percent. Any idea anyone why’s that so?

Let me give you my personal ramble through the conference:

On Monday my body partally participated in the Agile Alliance’s full day workshop on Functional Testing Tools. Although this name might not sound like the most sexy thing in the world, the group comprised many of the innovative minds of the field. It’s a pity that I was so jet-lag-struck that I had to go for a short 2-hour-nap during lunch; therefore my active participation was almost non-existant. Here are some of the results.

Tuesday was my personal presentation day. Given a competition of 44 concurrent talks, I was very content with having 30+ (male only) listeners. The most fundamental questions coming from the audience was: (a) Would you say that TDD for Ajax works as smooth as in a Java only environment. (b) Would you really go for all the hassle to make your FIT-driven Selenium tests independent from “The Web” by simulating “The Web”? Given my current knowledge the short answers are: (a) It’s not as smooth but you it can be fun all the same. (b) I would strive very hard to avoid it.

Wednesday was my drifting day. I went in and out of sessions as I pleased – and I pleased the lot. However, Neal Ford’s talk on Ancient Philosophers & Blowhard Jamborees was so entertaining that I stayed to the end despite myself. Among many other citations and anecdotes he brought up a quote from Glenn Vanderburg:

Bad developers will move heaven & earth to do the wrong thing.

It’s a sad truth, because it eventually means that we cannot shield our software from incapable developers by technical means like stricter type systems, higher abstractions & tighter code ownership. At the end of the day we have to get rid of the NNPPs provide the NNPPs with alternative career paths. Will they be less or more happy that way? How certain can I be that I haven’t joined that crowd yet?

To Everyone Their Own Mock Framework

July 30, 2008

Mine is called MockMe. It’s for JavaScript only.

I will explain everything and more after coming back from Toronto. See you there?

Agile 2008 in Toronto

July 15, 2008

This year’s Agile conference is looming quite large. I’m going to give a talk on “Test-Driven Ajax” on August, 5. That’s the good news and I’m looking very much forward to it. The bad news: There are 44 parallel sessions and I’ll have to compete with people like Mary Poppendieck, Dierk Riehle, James Newkirk, Dan North, Lisa Crispin, Brian Foote, Marc Evers, Mike Hill, Luke Hohman, Jutta Eckstein and Doug Rosenberg – just to name a few.

So, if you want to keep me away from lonesome talker’s depression just drop by in Sheraton Hall B and we both will have a good talk about the weather or alike.

Deadline for XP Days extended

July 13, 2008

Stefan Roock, program chair of this year’s XP Days Germany, has just announced that the submission deadline has been extended till July, 27:

Since the open reviewing process has worked well, the program comitee will need less time for the final review.

He is definitely right that opening the review process to all was a big improvement. I have two submissions in the run: “Behaviour-Driven Development” and “Test-Driven Ajax”. Go to http://www.conftool.com/xpdays2008/, register and tell me what you think of those.


Follow

Get every new post delivered to your Inbox.