Friday, 6 June 2008

Test Driven JavaScript using QUnit

I have a little project that I started writing in OpenLaszlo. I chose OpenLaszlo because I thought I could script it in standard JavaScript but during the development of my minor app I found a few errors with the OpenLaszlo JavaScript implementation and the project stalled. Now, having started a new job, where the development team use splendid new technologies like QUnit, and JQuery, I resurrected my app.

So I present, to you, some notes on my experience of Test Driven JavaScript using QUnit.



I class myself as a real novice with JavaScript. My best JavaScript app yet has major issues with Internet Explorer and so I guess I should really class myself as pretty rubbish at JavaScript... however I remain undeterred and convinced I can learn this stuff.

Fortunately the development team gave me a quick demo of QUnit at work so I understood a little about the technology, and no better teacher than experience can help me understand, so time to dabble.

As a novice, I followed the instructions on the QUnit site and created a basic test page (called test_eprime.htm).

 

<html>
<head>
<script src="jquery-latest.js"></script>
<link media="screen" href="testsuite.css" type="text/css" rel="stylesheet">
<script src="testrunner.js"></script>

<script>

$(document).ready(function(){

});

</script>

<h1>E-Prime JavaScript Tests</h1>
<h2 id="banner"></h2>
<h2 id="userAgent"></h2>
<ol id="tests"></ol>
<div id="main"></div>
</body>
</html>

 


And when viewed in a browser this gives me the joyous news that I have 0 tests of 0 failed.


 



 


Woo Hoo!


In order to support this my code folder has:



 


So now I'll create my first test. I do this by adding all my tests between the magic lines in the above test frame work html


 


<script>

$(document).ready(function(){

**** I add all my code in here ****

});

</script>

 


QUnit has the concept of modules which 'chunk' tests together. So I create an html formatting module, for all my HTML formatting tests.


 


module("HTML Formatting");

 


And then I'll write my first test...


 



test("html char conversion", function(){
    equals("&gt;",convertToHTMLIfRequired('>'));
});

 


I added a new 'test' to the set of tests. The test had the name "html char conversion". I created the code of the test as an unnamed function. The purpose of the test? To check the function convertToHTMLIfRequired function returns &gt; when called with the parameter '>'


So now I save my test_eprime.htm file and reload it into FireFox.


And voila...


 



 


...my test failed. Hopefully as you expected, after all I didn't write any code.


So off I go to my trusty text editor and create a new file called eprime.js which looks like this


 



 function convertToHTMLIfRequired(c){
return '&gt;';
}

 


Run the tests again by refreshing the page in the browser. And...


 



 


Wha! Oh, I forgot to include eprime.js into my test_eprime.htm, OK, easy fix.


 


...
<script src="testrunner.js"></script>
<script src="eprime.js"></script>
...

 


Refresh to run the tests.


 



 


Alright! High Five! Watch as I do my "successful test passing" dance.


And so we move on.


Back into the tests and make that a little more robust...


 


test("html char conversion", function(){
    equals("&gt;",convertToHTMLIfRequired('>'));
equals("&lt;",convertToHTMLIfRequired('<'));
});

 


Refresh the browser and my tests fail. As we would hope.


 



 



Eagle eyed readers will note that I got the 'expected' and 'actual' parameters the wrong way around. I should have used the format...


       equals(<actual>,<expected>);


I could blame my error on the QUnit front page which shows the following example code...

   equals( "hello", value, "We expect value to be hello" );

But I'd feel petty and, since I didn't read the manual, I take the blame.


 


So I go away and add more code, like a good TDD practitioner.


 


 function convertToHTMLIfRequired(c){
if(c=='<')
return '&lt;';

if(c=='>')
return '&gt;';
}

Refresh the browser...


 



 


Woo hoo! Cue "Successful test passing" dance... and so on, and so on...


I then follow this with more TDD iterations, which worked out rather well. But so as not to bore you, I shall conclude.


 


Conclusions


The eagle eyed among you will have said "Why does it keep saying 0 tests of 0 failed, even when 1 failed?" and the answer I respond with reads "I don't know, I haven't read the manual yet".


And despite the "0 tests of 0 failed", I like:



  • this unit test harness,
  • how easy I found writing JavaScript using TDD with QUnit,
  • TDD JavaScript,
  • the fact that my IDE consists of a free text editor notepad++, and a free Browser,
  • the fact that I haven't had to read the manual yet, and have managed to make a lot of progress,
  • that I can keep running my tests easily,
  • by loading my test page into different browers I can check for browser compatibility

I will now go off and finish my little e-prime application in 'proper' JavaScript, using TDD and shall forget about OpenLaszlo for the moment. (I'll write up the reasons for this on CompendiumDev at some point).


More TDD JavaScript posts coming soon. Will I ever get rid of "0 tests of 0 failed"? ... stay tuned thrill seekers.


 


Downloads:


  • jquery-latest.js
  • testrunner.js
  • testsuite.css
  • test_eprime.htm

  • eprime.js
  • 4 comments:

    1. Nice post Alan,

      Thanks for the heads-up on QTest. What would you say are the benefits of QTest over jsUnit?

      The QTest uses semantics reminiscent of of a framework I wrote some time ago for some Perl developers who were more used to using Test::More... http://www.testingreflections.com/node/view/5333
      (please excuse the formatting issues on that link - trying to fix them)

      Love posts like this one... nothing evil about them :-)

      Antony Marcano


      Thanks Antony,

      I only looked at JSUnit once about a year ago and for some reason I found it hard to get my head around, I don't quite know what I really found difficult, since I just had another look and it seemed simple enough. I do plan to have another look at JSUnit.

      Other blogs I read describe JSUnit as slow, and difficult to use for Ajax, but I cannot corroborate that from experience.

      JSUnit has not had an update for over 2 years (according to the sourceforge news).

      JSUnit being used as part of JQuery testing gives it a whole lot of Qudos.

      Some other discussions of JSUnit vs Qunit.

      Hope that helps.

      Alan

      ReplyDelete
    2. don't feel too bad about the '0 tests of 0 failed' -- after all, the example on jQuery's QUnit page has the same error :)

      Thanks Jared. I shall assume that I didn't do something wrong then. :)

      Alan

      ReplyDelete
    3. The ‘0 tests of 0 failed’ problem happens because testrunner.js calls runTest() on document ready. Since that script is loaded before your document ready code, the results are generated before your tests are run.

      To get rid of the problem, run your tests as a script tag in the head section, which means they run before doc ready.

      Thanks for the article, it was a useful intro =)

      Fantastic info thanks.

      Comment out...
      // $(document).ready(function(){

      and the corresponding closing tags

      //});

      And suddenly I have information...

      Tests completed in 125 milliseconds.
      0 tests of 116 failed.

      Excellent - thanks.

      ReplyDelete