Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Web Developer

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « PASS Summit 2011 BlessingsGoogle realizes that JavaScript is a dead end programming language, to be replaced by Dart a new language »
    comments

    Recently I decided to start doing JavaScript code katas. I've been using JavaScript for around ten years, but there there are still a lot of aspects I don't know well or that I could use more practice in. Case in point, I had never used a unit testing framework with javascript. Having never unit tested JavaScript before, I used a scientific tool to carefully select from amongst the numerous unit testing packages available.

    I typed "javascript unit testing" into Google and started reading.

    jsTestDriver

    jsTestDriver was listed on a wide number of sites as one of the top JavaScript unit testing tools and fit an initial requirement I set myself of running outside of a browser. jsTestDriver runs as a client-server pair, the client sending tests to the server, which then runs them on a captured browser. The advantage of this method is it can easily be integrated with a code editor or as part of an automated build.

    The jsTestDriver site includes plugins for Eclipse, Maven, and IntelliJ. I also found an article on using it with Visual Studio and it was fairly easy setting it up as a user tool in EditPlus.

    Screenshot of EditPlus

    Screenshot of EditPlus Settings

    Though I'm not using the feature, jsTestDriver provides a flag to specify an output file for the results, enabling us to use it as part of a continuous build.

    The Setup

    Setting up jsTestDriver on my system was fairly straightforward.

    1. Download Java - Visit java.com and download the appropriate installer, run the installer, remember to go into the control panel and fiddle with Java's update settings
    2. Download the jar file - Visit the project on Google and download a copy of the jar file (I used the self-contained version)
    3. Create folders - Create a top level folder and two sub folders (for instance, src and src-test). Put the jar in the top level folder
    4. Create a conf file - I used the one in the Getting Started Guide as a starting point

    At this point we should be able to fire up the server for the first time and verify everything is ready to go. I created a .cmd file on my system for the server so I could easily start it:

    1. "C:\Program Files (x86)\Java\jre6\bin\java" -jar JsTestDriver-1.3.2.jar --port 4224 --browser "C:\Documents and Settings\Tarwn\Local Settings\Application Data\Google\Chrome\Application\chrome.exe"

    What this does is starts the jsTestDriver jar on port 4224 and also automatically starts up an instance of chrome that will be captured by the server to run tests. I was initially using Firefox but jsTestDriver can't intercept the console log the way it can with Chrome, so I wasn't getting very good output for failed or errored tests.

    Next I created a .cmd file to run all the tests in my folders:

    1. "C:\Program Files (x86)\Java\jre6\bin\java" -jar JsTestDriver-1.3.2.jar --tests all
    2. pause

    This tells jsTestDriver to run all available tests (based on the settings in the conf) using a jsTestDriver server on port 4224. I ended up not using this cmd file very frequently, as it was much handier to be able to run them from a key command inside my editor.

    Writing Tests

    Once we have gotten this far, we can start writing some simple tests.

    In each directory (src and src-test), create a file named "mystuff.js".

    src/mystuff.js

    1. myAwesomeApp = {};
    2.  
    3. myAwesomeApp.MyAwesomeClass = function(){};
    4.  
    5. myAwesomeApp.MyAwesomeClass.prototype.add = function(num0, num1){
    6.     return num0 + num1;
    7. };

    src-test/mystuff.js

    1. TestCase("Sample Test Case",{
    2.  
    3.     "test Number plus Zero Equals Number": function(){
    4.         var adder = new myAwesomeApp.MyAwesomeClass();
    5.         assertEquals(5, adder.add(5,0));
    6.     },
    7.     "test Number plus Number Equals Sum": function(){
    8.         var adder = new myAwesomeApp.MyAwesomeClass();
    9.         assertEquals(8, adder.add(5,3));
    10.     },
    11.     "test Zero plus Number Equals Number": function(){
    12.         var adder = new myAwesomeApp.MyAwesomeClass();
    13.         assertEquals(5, adder.add(0,5));
    14.     },
    15.     "test Number plus Negative of Number Equals Zero": function(){
    16.         var adder = new myAwesomeApp.MyAwesomeClass();
    17.         assertEquals(0, adder.add(5,-5));
    18.     },
    19.     "test Fails miserably": function(){
    20.         fail("miserably");
    21.     }
    22. });

    JavaScript provides a number of different methods to define objects with functions, in the source class I used the prototype method and in the tests file I used an object literal. For jsTestDriver, the important part is that the tests in the object we pass to TestCase begin with the word test, and the object literal method seemed like a friendlier layout for a test file.

    Running Tests

    Once we have the two files in place, start the server by issuing the following command (or creating the cmd file like me):

    1. "C:\Program Files (x86)\Java\jre6\bin\java" -jar ../JsTestDriver-1.3.2.jar --port 4224 --browser "C:\Documents and Settings\Tarwn\Local Settings\Application Data\Google\Chrome\Application\chrome.exe"

    You will need to update the browser and java paths to reflect your own.

    Once the browser has started and it has been captured by the server for testing, it will look like this:

    Chrome captured by jsTestDriver Server

    Chrome captured by jsTestDriver Server

    Now we can run our tests by issuing the following command:

    1. "C:\Program Files (x86)\Java\jre6\bin\java" -jar ../JsTestDriver-1.3.2.jar --tests all

    Again, you will need to change the java path to reflect your own (or remove it if you have added it to your PATH variable).

    The results should look something like this:

    ....F
    Total 5 tests (Passed: 4; Fails: 1; Errors: 0) (0.00 ms)
      Chrome 13.0.782.220 Windows: Run 5 tests (Passed: 4; Fails: 1; Errors 0) (0.00 ms)
        Object Literal Test Case.test Fails miserably failed (0.00 ms): AssertError: miserably
          AssertError: miserably
              at Object.test Fails miserably (http://localhost:4224/test/src-test/mystuff.js:22:3)
    
    Tests failed: Tests failed. See log for details.
    

    The top reflects the tests that have run at a glance with .s for passing tests, Fs for failed, and E for errored. Afterwards we get a summary of the total counts and then a section for the one browser we ran with. jsTestDriver allows you to capture multiple browsers, so we could configure this to run our tests across chrome, firefox, and IE simultaneously.

    jsTestDriver also supports "setup" and "teardown" functions to run before and after tests.

    Qunit

    Qunit is a browser-based solution that was built to unit test the jQuery framework. Qunit has fewer requirements to run, but because it runs directly in a browser it means we have to switch windows and refresh in order to get an updated test run.

    The Setup

    Because Qunit will run in our browser, there are relatively few requirements and unlike jsTestDriver, none of them are installations.

    1. We already made our folders, so nothing to do here
    2. Download the necessary include files to the top level: qunit.js and qunit.css (I renamed mine without the -git)
    3. Create an empty html file in the top level

    The empty file will be our test runner. Update the file to look like this:

    1. <DOCTYPE html>
    2. <html>
    3. <head>
    4.     <script src="http://code.jquery.com/jquery-1.6.4.min.js" type="text/javascript"></script>
    5.     <script src="qunit.js" type="text/javascript"></script>
    6.     <link rel="stylesheet" media="all" href="qunit.css" />
    7.  
    8.     <script src="src/mystuff.js" type="text/javascript"></script>
    9.     <script src="src-test/mystuff_qunit.js" type="text/javascript"></script>
    10.  
    11. </head>
    12. <body>
    13.     <h1 id="qunit-header">MyStuff</h1>
    14.     <h2 id="qunit-banner"></h2>
    15.     <h2 id="qunit-userAgent"></h2>
    16.     <ol id="qunit-tests"></ol>
    17. </body>
    18. </html>

    As you can see, we are referencing a CDNed version of jQuery, the local qunit files we downloaded, our source file, and a test js file we haven't created yet. The remainder of the HTML will be used by Qunit to display the results.

    Writing Tests

    Writing test in Qunit is pretty straightforward. Since we already have the src/mystuff.js file from above, we can jump right in and create a qunit version of our test cases.

    src-test/mystuff_qunit.js

    1. module("Sample Test Case");
    2.  
    3. test("Number plus Zero Equals Number", function(){
    4.     var adder = new myAwesomeApp.MyAwesomeClass();
    5.     equals( adder.add(5,0),5);
    6. });
    7.  
    8. test("Number plus Number Equals Sum", function(){
    9.     var adder = new myAwesomeApp.MyAwesomeClass();
    10.     equals(adder.add(5,3),8);
    11. });
    12.  
    13. test("Zero plus Number Equals Number", function(){
    14.     var adder = new myAwesomeApp.MyAwesomeClass();
    15.     equals(adder.add(0,5),5);
    16. });
    17.  
    18. test("Number plus Negative of Number Equals Zero", function(){
    19.     var adder = new myAwesomeApp.MyAwesomeClass();
    20.     equals(adder.add(5,-5),0);
    21. });
    22.  
    23. test("Fails miserably", function(){
    24.     ok(false,"miserably");
    25. });

    Qunit's equals method has it's actual and expected arguments reversed from jsTestDriver, instead expecting them in this order: Qunit.equals(actual, expected). I didn't originally notice this and had to update both the jsTestDriver test mapping script and the sample above (here and in bitbucket).

    Running Tests

    Opening the testrunner html file, we should now see it display a block for each test that we have defined above.

    QUnit Results

    QUnit Results

    Failed tests automatically display details. Any test can be toggled open/closed by clicking it's name, and a handy "rerun" button lets us re-run a single test.

    Combining Them

    By writing a small amount of glue script, I was able to re-use my jsTestDriver tests in Qunit. Since I am currently only using a small subset of assertions and using the object literal method, the glue script is limited to only exactly what I needed.

    Add this file to the top level folder:
    jsTestDriverInQunit.js

    1. /* bare minimum to run jsTestDriver tests as Qunit tests */
    2. function TestCase(name, tests){
    3.         if(tests != null)
    4.                 module(name);
    5.         for(var key in tests){
    6.                 if(tests[key] instanceof Function && key.indexOf("test") == 0){
    7.                         test(key,tests[key]);
    8.                 }
    9.         }
    10.         return function(){};
    11. }
    12.  
    13. function assertEquals(arg0,arg1){
    14.         equals(arg1,arg0);
    15. }
    16. function fail(msg){
    17.         ok(false,msg);
    18. }

    And update the testrunner HTML file we created to look like this:

    1. <DOCTYPE html>
    2. <html>
    3. <head>
    4.     <script src="http://code.jquery.com/jquery-1.6.4.min.js" type="text/javascript"></script>
    5.     <script src="qunit.js" type="text/javascript"></script>
    6.     <script src="jsTestDriverInQunit.js" type="text/javascript"></script>
    7.     <link rel="stylesheet" media="all" href="qunit.css" />
    8.  
    9.     <script src="src/mystuff.js" type="text/javascript"></script>
    10.     <script src="src-test/mystuff.js" type="text/javascript"></script>
    11. </head>
    12. <body>
    13.     <h1 id="qunit-header">MyStuff</h1>
    14.     <h2 id="qunit-banner"></h2>
    15.     <h2 id="qunit-userAgent"></h2>
    16.     <ol id="qunit-tests"></ol>
    17. </body>
    18. </html>

    And now whether we run the jsTestDriver client/server or open the Qunit file, we will be running the same exact set of tests.

    There is also a project that translates Qunit tests into tests that can be run with jsTestDriver.

    All of the source code for this post (as well as the content of a couple programming katas) can be found in my javascript repository on BitBucket. The folder structure is slightly different to cut down on duplication of resources.

    About the Author

    User bio imageEli delivers software and technology solutions for a living. His roles have included lone developer, accidental DBA, team lead, and even unintentional Solaris consultant once. With experience in adhoc, Lean, and Agile environments across NSF grants, SaaS products, and in-house IT groups, he is just as willing to chat about the principles of Lean or Continuous Delivery as he is to dive into Azure, SQL Server, or the last ATDD project he created.
    Social SitingsTwitterLinkedInHomePagedeliciousLTD RSS Feed
    InstapaperVote on HN

    6 comments

    Comment from: Erik [Member] Email
    Erik Which did you like better?
    09/26/11 @ 13:39
    Comment from: Eli Weinstock-Herman (tarwn) [Member]
    Eli Weinstock-Herman (tarwn) I liked them about the same, for different reasons/purposes. jsTestDriver's downsides were the reliance on Java and the fact that it still required a browser, but the ability to test against multiple browsers was also a positive. What bothered me about Qunit was the need to switch screens to see the results and the fact that the display of the tests seems to get unwieldy when used for larger numbers of tests (to the point where I considered going in and customizing the layout to fit a larger set more easily or simply hiding passed tests and showing a count).

    That's not to say I disliked either, I just found those points to be a little clumsy. Someone also pointed me to Jasmine (http://pivotal.github.com/jasmine/) which, though it's behavior-driven, may fill in some of the gaps in between these two, I'll have to see. Also been planning on looking more into sql unit testing, not sure which will happen first. I still haven't gotten around to doing write-ups on Selenium yet, and I had planned on doing at least 2 on that. The backlog overfloweth.
    09/26/11 @ 13:52
    Comment from: Lumbendil [Visitor] · http://deliriosbyn.blogspot.com
    Lumbendil Have you heard of Node.js and it's Assert class? You could test that aswell to see if you like it.
    09/27/11 @ 10:13
    Comment from: Eli Weinstock-Herman (tarwn) [Member]
    Eli Weinstock-Herman (tarwn) I'm still pretty new to node.js and hadn't heard of the assert class. Although now that you've mentioned it, it seems kind of obvious that node.js would be a good platform for headless js testing since all you need is the binary. Hmm, I may have a new project for this weekend, thanks :)
    09/27/11 @ 10:33
    Comment from: Eli Weinstock-Herman (tarwn) [Member]
    Eli Weinstock-Herman (tarwn) Another one that someone sent me this week (I haven't tried it myself yet) is Testling: http://www.catonmat.net/blog/announcing-testling/

    This one is a remote test server that will run tests across a variety of platforms. Obviously this adds some extra dependencies and time to your testing, but it adds the ability to easily test multi-platform.
    10/26/11 @ 07:42
    Comment from: Lumbendil [Visitor] · http://deliriosbyn.blogspot.com
    Lumbendil in my opinion, if you need to test compatiblity of a javascript code across several browsers, unless you're developing something like jQuery or another complex app, you'd be better off testing the behaviour via Selenium.
    10/31/11 @ 02:16

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)