JavaScript Unit Testing Part 2: JSSpec

In this post we will examine the 2nd of 4 JavaScript Unit Testing frameworks... JSSpec.

Previous parts of this series...

In subsequent posts we will cover QUnit, and YUI Test.

<p>I like this Unit Testing framework a lot more than JsUnit for the following reasons...</p><ul><li>As you can see from the screenshot below, it has a nice interactive Test Runner</li>   <li>The testing API has an easy to read <a href="http://en.wikipedia.org/wiki/Fluent_interface">Fluent Interface</a> (a.k.a. It reads like English)</li>   <li>The project appears to still be active... the latest version was available on <a href="http://code.google.com/p/jsspec/downloads/list">Sep 23, 2008</a></li>   <li>The test files don't need to be hosted in a web server in order to run (unlike JsUnit).</li></ul><div><a href="http://2.bp.blogspot.com/_L6DiZQsfJzs/Seh2yK6z7KI/AAAAAAAAGyY/PJKcwcfoVMc/s1600-h/PigLatin.PNG" imageanchor="1"><img border="0" src="http://2.bp.blogspot.com/_L6DiZQsfJzs/Seh2yK6z7KI/AAAAAAAAGyY/PJKcwcfoVMc/s400/PigLatin.PNG"></a></div> <p>Ok, ok, enough talk. Lets get down to using this framework...</p> <p>I added functionality to the nasty Pig Latin JavaScript to not only translate words, but also sentences.*</p> <p>*Note: Yet again, this code is not optimal and it will be refactored in a future post.</p> <pre><br>function EnglishToPigLatin() {<br>    this.CONSONANTS = 'bcdfghjklmnpqrstvwxyz';<br>    this.VOWELS = 'aeiou';<br>    this.Translate = function(english, splitType) {<br>        var translated = '';    <br><br>        console.log('English: ', english);<br>        var words = english.split(/\s+/);<br>        console.log('Split Words: ', words);<br>        for (var i = 0; i < words.length; ++i) {<br>            console.log('Word ', i, ': ', words[i]);<br>            translated += this.TranslateWord(words[i]);<br>            if (i+1 < words.length) translated += ' ';<br>        }<br>        console.log('Translated: ', translated);<br>        console.log('----------');<br><br>        return translated;<br>    }<br>    this.TranslateWord = function(english) {<br>       /*const*/ var SYLLABLE = 'ay';<br><br>       var pigLatin = '';<br><br>       if (english != null && english.length > 0 && <br>          (this.VOWELS.indexOf(english[0].toLowerCase()) > -1 || this.CONSONANTS.indexOf(english[0].toLowerCase()) > -1 )) {<br>          if (this.VOWELS.indexOf(english[0].toLowerCase()) > -1) {<br>             pigLatin = english + SYLLABLE;<br>          } else {      <br>             var preConsonants = '';<br>             for (var i = 0; i < english.length; ++i) {<br>                if (this.CONSONANTS.indexOf(english[i].toLowerCase()) > -1) {<br>                   preConsonants += english[i];<br>                   if (preConsonants.toLowerCase() == 'q' && i+1 < english.length && english[i+1].toLowerCase() == 'u') {<br>                      preConsonants += 'u';<br>                      i += 2;<br>                      break;<br>                   }<br>                } else {<br>                   break;<br>                }<br>             }<br>             pigLatin = english.substring(i) + preConsonants + SYLLABLE;<br>          }<br>       }<br><br>       return pigLatin;    <br>    }<br>} </pre> <p>Like I said before, JSSpec provides a nicer Fluent Interface that makes the tests read more like English. The follow are several sets of Unit Tests to exercise the existing functionality, plus the new feature I added since the last post.</p> <pre><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><br><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko"><br><head><br><meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /><br><title>JSSpec results</title><br><link rel="stylesheet" type="text/css" href="JSSpec.css" /><br><script type="text/javascript" src="diff_match_patch.js"></script><br><script type="text/javascript" src="JSSpec.js"></script><br><script type="text/javascript" src="PigLatinBad.js"></script><br><script type="text/javascript">// <![CDATA[<br>describe('Invalid Arguments', {<br>    before_each : function() { englishToPigLatin = new EnglishToPigLatin(); },<br>    'Passing Null Should Return Blank': function() {<br>        value_of(englishToPigLatin.TranslateWord(null)).should_be('');<br>    },<br>    'Passing Blank Should Return Blank': function() {<br>        value_of(englishToPigLatin.TranslateWord('')).should_be('');<br>    },    <br>    'Passing 1234567890 Should Return Blank': function() {<br>        value_of(englishToPigLatin.TranslateWord('1234567890')).should_be('');<br>    },<br>    'Passing ~!@#$%^&*()_+ Should Return Blank': function() {<br>        value_of(englishToPigLatin.TranslateWord('~!@#$%^&*()_+')).should_be('');<br>    }    <br>})<br><br>describe('Consonant Words', {<br>    before_each : function() { englishToPigLatin = new EnglishToPigLatin(); },<br>    'Passing Beast Should Return Eastbay': function() {<br>        value_of(englishToPigLatin.TranslateWord('beast')).should_be('eastbay');<br>    },<br>    'Passing Dough Should Return Oughday': function() {<br>        value_of(englishToPigLatin.TranslateWord('dough')).should_be('oughday');<br>    },<br>    'Passing happy Should Return appyhay': function() {<br>        value_of(englishToPigLatin.TranslateWord('happy')).should_be('appyhay');<br>    },<br>    'Passing question Should Return estionquay': function() {<br>        value_of(englishToPigLatin.TranslateWord('question')).should_be('estionquay');<br>    },<br>    'Passing star Should Return arstay': function() {<br>        value_of(englishToPigLatin.TranslateWord('star')).should_be('arstay');<br>    },<br>    'Passing three Should Return eethray': function() {<br>        value_of(englishToPigLatin.TranslateWord('three')).should_be('eethray');<br>    }<br>})<br><br>describe('Vowel Words', {<br>    before_each : function() { englishToPigLatin = new EnglishToPigLatin(); },<br>    'apple Should Return appleay': function() {<br>        value_of(englishToPigLatin.TranslateWord('apple')).should_be('appleay');<br>    },<br>    'elijah Should Return elijahay': function() {<br>        value_of(englishToPigLatin.TranslateWord('elijah')).should_be('elijahay');<br>    },<br>    'igloo Should Return iglooay': function() {<br>        value_of(englishToPigLatin.TranslateWord('igloo')).should_be('iglooay');<br>    },<br>    'octopus Should Return octopusay': function() {<br>        value_of(englishToPigLatin.TranslateWord('octopus')).should_be('octopusay');<br>    },    <br>    'umbrella Should Return umbrellaay': function() {<br>        value_of(englishToPigLatin.TranslateWord('umbrella')).should_be('umbrellaay');<br>    }    <br>})<br><br>describe('Sentences', {<br>    before_each : function() { englishToPigLatin = new EnglishToPigLatin(); },<br>    "Passing 'hello' Should Return 'elloh'": function() {<br>        value_of(englishToPigLatin.Translate('hello')).should_be('ellohay');<br>    },<br>    "Passing 'hello world' Should Return 'elloh orldw'": function() {<br>        value_of(englishToPigLatin.Translate('hello world')).should_be('ellohay orldway');<br>    },<br>    "Passing 'hello world!' Should Return 'ellow orld!w'": function() {<br>        value_of(englishToPigLatin.Translate('hello world!')).should_be('ellohay orld!way');<br>    },<br>    "Passing 'Hello World' Should Return 'elloH orldW'": function() {<br>        value_of(englishToPigLatin.Translate('Hello World')).should_be('elloHay orldWay');<br>    },    <br>    "Passing 'Hello World!' Should Return 'elloH orld!W'": function() {<br>        value_of(englishToPigLatin.Translate('Hello World!')).should_be('elloHay orld!Way');<br>    }<br>})<br>// ]]></script><br></head><br><body><div style="display:none;"><p>A</p><p>B</p></div></body><br></html></pre> <p>There are other asserts that can be made that I didn't make use of in the above same. Here are some examples... (taken from the <a href="http://jania.pe.kr/aw/moin.cgi/JSSpec/Manual">JSSpec Manual</a>)</p><ul><li>value_of('Hello'.toLowerCase()).should_be('hello');</li>   <li>value_of([1,2,3]).should_be([1,2,3]);</li>   <li>value_of(new Date(1979,03,27)).should_be(new Date(1979,03,27));</li>   <li>value_of([]).should_be_empty();</li>   <li>value_of(1 == 1).should_be_true();</li>   <li>value_of(1 != 1).should_be_false();</li>   <li>value_of("Hello").should_have(5, "characters");</li>   <li>value_of([1,2,3]).should_have(3, "items")</li>   <li>value_of({name:'Alan Kang', email:'jania902@gmail.com', accounts:['A', 'B']}).should_have(2, "accounts");</li>   <li>value_of([1,2,3]).should_have_exactly(3, "items");</li>   <li>value_of([1,2,3]).should_have_at_least(2, "items");</li>   <li>value_of([1,2,3]).should_have_at_most(4, "items");</li>   <li>value_of([1,2,3]).should_include(2);</li>   <li>value_of([1,2,3]).should_not_includ</li>   <li>value_of({a: 1, b: 2}).should_include("a");</li>   <li>value_of({a: 1, b: 2}).should_not_include("c");</li></ul><p>As you can see, this is a very powerful easy to read and execute testing framework. Of those frameworks I have tested thus far, I recommend it above the others (at this point I've only covered JsUnit).</p>
Read More »

My First Podcast Interview

A good friend of mine, Tanton Gibbs (@tgibbs), from Microsoft has started a new Podcast series called New Tech Cast.

In these podcasts, I'm going to be interviewing up and comers in the software development world. These industrious developers will have their fingers on the pulse of today's tech and should provide great insight into the things to come.

I was flattered to be chosen for his first Podcast interview. In the podcast we discussed my history, various technologies that I use (ASP.NET MVC, jQuery, etc...), and a variety of other things.

You can download and listen to the podcast on his new website.

Read More »

JavaScript Unit Testing Part 1: JsUnit

In this post we will examine the 1st of 4 JavaScript Unit Testing frameworks... JsUnit.

<p>In subsequent posts we will cover <a target="_blank" href="http://jania.pe.kr/aw/moin.cgi/JSSpec">JSSpec</a>, <a target="_blank" href="http://docs.jquery.com/QUnit">QUnit</a>, and <a target="_blank" href="http://developer.yahoo.com/yui/yuitest/">YUI Test</a>.</p>    <p>First of all, lets define some JavaScript code that we want to Unit Test. I wrote the following Pig Latin JavaScript utility for the sole purpose of this Unit Testing series… </p> <p>*Note: I am aware the code needs to be refactored. We will address that in a future blog post :)  </p>    <pre><br>/*const*/ var CONSONANTS = 'bcdfghjklmnpqrstvwxyz';<br>/*const*/ var VOWELS = 'aeiou';<br><br>function EnglishToPigLatin(english) {<br>   /*const*/ var SYLLABLE = 'ay';<br><br>   var pigLatin = '';<br><br>   if (english != null && english.length > 0 && <br>      (VOWELS.indexOf(english[0]) > -1 || CONSONANTS.indexOf(english[0]) > -1 )) {<br>      if (VOWELS.indexOf(english[0]) > -1) {<br>         pigLatin = english + SYLLABLE;<br>      } else {      <br>         var preConsonants = '';<br>         for (var i = 0; i < english.length; ++i) {<br>            if (CONSONANTS.indexOf(english[i]) > -1) {<br>               preConsonants += english[i];<br>               if (preConsonants == 'q' && i+1 < english.length && english[i+1] == 'u') {<br>                  preConsonants += 'u';<br>                  i += 2;<br>                  break;<br>               }<br>            } else {<br>               break;<br>            }<br>         }<br>         pigLatin = english.substring(i) + preConsonants + SYLLABLE;<br>      }<br>   }<br><br>   return pigLatin;<br>}</pre> <p>Next we need to define a set of Unit Tests using JsUnit. I am using JsUnit 2.2 Alpha 11 for this example.</p> <p>In order to create the Unit Tests we need to know the business rules for the Pig Latin method… </p> <ol><li>In words that begin with <a href="http://en.wikipedia.org/wiki/Consonant">consonant</a> sounds, the initial consonant or <a href="http://en.wikipedia.org/wiki/Consonant_cluster">consonant cluster</a> or diagraph is moved to the end of the word, and "ay" is added…</li>   <li>In words that begin with <a href="http://en.wikipedia.org/wiki/Vowel">vowel</a> sounds or <a href="http://en.wikipedia.org/wiki/Silent_letter">silent consonants</a>, the syllable "ay" is added to the end of the word. In some dialects, to aid in pronunciation, an extra consonant is added to the beginning of the suffix.</li></ol><p>Now that we know the rules, lets start making some Unit Tests…</p> <pre><html><br> <head><br>   <title>Test Page for EnglishToPigLatin(english)</title><br>   <link rel="stylesheet" type="text/css" href="../css/jsUnitStyle.css"><br>   <script language="JavaScript" type="text/javascript" src="../app/jsUnitCore.js"></script><br>   <script language="JavaScript" type="text/javascript" src="./PigLatin.js"></script><br> </head><br> <body><br>  <script language="javascript"><br>   function testPassingNullShouldReturnBlank() {<br>      assertEquals('null returns a blank', '', EnglishToPigLatin(null));<br>   }<br><br>   function testPassingBlankShouldReturnBlank() {<br>      assertEquals('blank returns a blank', '', EnglishToPigLatin(''));<br>   }<br><br>   function testConsonantBeastShouldReturnEastbay() {<br>      assertEquals('beast returns eastbay', 'eastbay', EnglishToPigLatin('beast'));<br>   }   <br><br>   function testConsonantDoughShouldreturnOughday() {<br>      assertEquals("dough returns oughday", 'oughday', EnglishToPigLatin('dough'));<br>   }<br><br>   function testConsonantHappyShouldReturnAppyhay() {<br>      assertEquals("happy returns appyhay", 'appyhay', EnglishToPigLatin('happy'));<br>   }        <br><br>   function testConsonantsQuestionShouldReturnEstionquay() {<br>      assertEquals("question returns estionquay", 'estionquay', EnglishToPigLatin('question'));<br>   }<br><br>   function testConsonantsStarShouldReturnArstay() {<br>      assertEquals("star returns arstay", 'arstay', EnglishToPigLatin('star'));<br>   } <br><br>   function testConsonantsThreeShouldReturnEethray() {<br>      assertEquals("three returns eethray", 'eethray', EnglishToPigLatin('three'));<br>   }<br><br>   function testVowelAppleShouldReturnAppleay() {<br>      assertEquals("apple returns appleay", 'appleay', EnglishToPigLatin('apple'));<br>   }<br><br>   function testVowelElijahShouldReturnElijahay() {<br>      assertEquals("elijah returns elijahay", 'elijahay', EnglishToPigLatin('elijah'));<br>   }<br><br>   function testVowelIglooShouldReturnIglooay() {<br>      assertEquals("igloo returns iglooay", 'iglooay', EnglishToPigLatin('igloo'));<br>   }<br><br>   function testVowelOctopusShouldReturnOctopusay() {<br>      assertEquals("octopus returns octopusay", 'octopusay', EnglishToPigLatin('octopus'));<br>   }<br><br>   function testVowelUmbrellaShouldReturnUmbrellaay() {<br>      assertEquals("umbrella returns umbrellaay", 'umbrellaay', EnglishToPigLatin('umbrella'));<br>   }<br><br>   function testPassingNumberShouldReturnBlank() {<br>      assertEquals("1234567890 returns blank", '', EnglishToPigLatin('1234567890'));<br>   }<br><br>   function testPassingSymbolsShouldReturnBlank() {<br>      assertEquals("~!@#$%^&*()_+ returns blank", '', EnglishToPigLatin('~!@#$%^&*()_+'));<br>   }<br>    </script><br> </body><br></html><br></pre> <p>There are several different types of asserts that JsUnit supports...</p><ol><li>assert([comment], booleanValue)</li>   <li>assertTrue([comment], booleanValue)</li>   <li>assertFalse([comment], booleanValue)</li>   <li>assertEquals([comment], value1, value2)</li>   <li>assertNotEquals([comment], value1, value2)</li>   <li>assertNull([comment], value)</li>   <li>assertNotNull([comment], value)</li>   <li>assertUndefined([comment], value)</li>   <li>assertNotUndefined([comment], value)</li>   <li>assertNaN([comment], value)</li>   <li>assertNotNaN([comment], value)</li>   <li>fail(comment)</li></ol><p>JsUnit has a testRunner to execute all of your Unit Tests. If all is well, your status bar will be green. If any asserts failed, they will be displayed in a list control where any assert comment can be retrieved</p> <a href="http://lh3.ggpht.com/_L6DiZQsfJzs/SdrV0Axc9bI/AAAAAAAAGw0/PH8z74w0rag/s1600-h/testRunner%5B3%5D.png"><img title="testRunner" border="0" alt="testRunner" src="http://lh6.ggpht.com/_L6DiZQsfJzs/SdrV4U9-qbI/AAAAAAAAGw4/4NaS4uIHNEs/testRunner_thumb%5B1%5D.png?imgmax=800" width="404" height="242"></a> <p>Overall, JsUnit is a decent Unit Testing framework for JavaScript. You can also bundle tests into suites and run multiple suites. As most testing frameworks, you can also use setUp() and tearDown() methods to prepare the environment for each test method. </p>
Read More »

3 Biggest Software Lies

I ran across the following quote today and thought it was pretty funny…

3 Biggest Software Lies:

  1. The program’s fully tested and bug-free
  2. We’re working on the documentation
  3. Of course we can modify it!

Do you have any other items to add to the above list? If so, please share them in the comments :)

Read More »

JavaScript Unit Testing Frameworks

Not only should you have unit tests for your User Interface & Middle Tier code, but you should also consider unit testing your JavaScript code.

There are several different Unit Testing frameworks made for JavaScript that you have to choose from.

Note: In future posts I will show examples of how to use each of these frameworks… as for now, this is just an introduction to the tools I’ll be covering.

Framework Description
YUI Test

YUI Test is a testing framework for browser-based JavaScript solutions. Using YUI Test, you can easily add unit testing to your JavaScript solutions. While not a direct port from any specific xUnit framework, YUI Test does derive some characteristics fromnUnit and JUnit.

JsUnit JsUnit is a Unit Testing framework for client-side (in-browser) JavaScript. It is essentially a port of JUnit to JavaScript. Also included is a platform for automating the execution of tests on multiple browsers and mutiple machines running different OSs. Its development began in January 2001.
QUnit QUnit is the unit testrunner for the jQuery project. It got promoted to a top-level project in May 2008 to make it easier to use in other projects, with focus on jQuery UI. Every plugin developer can leverage the testsuite to unit test their code.
JSSpec JSSpec is a Javascript BDD (Behavior Driven Development) framework.

Do you already use one of these frameworks? If so, which one do you prefer?

Is there another framework that you like that is better than the above listed?

Please leave a comment with your opinion :) Thanks!

Read More »