Monday, September 21, 2009

Unit Testing with jQuery using FireUnit & QUnit

Today’s screencast is the 5th in a series of developer Firefox Extensions. You can view my previous 3 short Screenr screencasts here…

    In addition to this post being part in a series of Firefox Extension screencasts, it is actually also the 3rd part of an old series looking through various JavaScript Unit Testing frameworks…
    The following short screencast will give a quick review of the FireUnit Firefox Firebug Add-on and also the QUnit Unit Testing framework for jQuery. In case you don’t want to watch the 4 minute screencast I thought I would go ahead and flush out the rest of this blog post with code, screenshots, and commentary.
      As a review, to exercise our Unit Testing frameworks we have been using a simple Pig Latin function as our testing subject.

    This code is not optimal and it will be refactored in a future post. So, please focus on the Unit Testing and not the actual Pig Latin function :)

    So, here is the Pig Latin converter function we will be using for our tests…

    function EnglishToPigLatin() {
        this.CONSONANTS = 'bcdfghjklmnpqrstvwxyz';
        this.VOWELS = 'aeiou';
        this.Translate = function(english, splitType) {
            var translated = '';    
            
            var words = english.split(/\s+/);
            for (var i = 0; i < words.length; ++i) {
                translated += this.TranslateWord(words[i]);
                if (i+1 < words.length) translated += ' ';
            }
            
            return translated;
        }
        this.TranslateWord = function(english) {
           /*const*/ var SYLLABLE = 'ay';
    
           var pigLatin = '';
              
           if (english != null && english.length > 0 && 
              (this.VOWELS.indexOf(english[0].toLowerCase()) > -1 || this.CONSONANTS.indexOf(english[0].toLowerCase()) > -1 )) {
              if (this.VOWELS.indexOf(english[0].toLowerCase()) > -1) {
                 pigLatin = english + SYLLABLE;
              } else {      
                 var preConsonants = '';
                 for (var i = 0; i < english.length; ++i) {
                    if (this.CONSONANTS.indexOf(english[i].toLowerCase()) > -1) {
                       preConsonants += english[i];
                       if (preConsonants.toLowerCase() == 'q' && i+1 < english.length && english[i+1].toLowerCase() == 'u') {
                          preConsonants += 'u';
                          i += 2;
                          break;
                       }
                    } else {
                       break;
                    }
                 }
                 pigLatin = english.substring(i) + preConsonants + SYLLABLE;
              }
           }
           
           return pigLatin;    
        }
    } 

    First we are going to write a simple set of 20 FireUnit tests that can be ran inside Firefox’s Firebug using the FireUnit Add-on.

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script type="text/javascript" src="PigLatinBad.js"></script>
        <script type="text/javascript">
            var englishToPigLatin = new EnglishToPigLatin();
    
            //Invalid Arguments
            fireunit.compare(englishToPigLatin.TranslateWord(null), '', 'Passing Null Should Return Blank');
            fireunit.compare(englishToPigLatin.TranslateWord(''), '', 'Passing Blank Should Return Blank');
            fireunit.compare(englishToPigLatin.TranslateWord('1234567890'), '', 'Passing 1234567890 Should Return Blank');
            fireunit.compare(englishToPigLatin.TranslateWord('~!@#$%^&*()_+'), '', 'Passing ~!@#$%^&*()_+ Should Return Blank');
    
            //Consonant Words
            fireunit.compare(englishToPigLatin.TranslateWord('beast'), 'eastbay', 'Passing Beast Should Return Eastbay');
            fireunit.compare(englishToPigLatin.TranslateWord('dough'), 'oughday', 'Passing Dough Should Return Oughday');
            fireunit.compare(englishToPigLatin.TranslateWord('happy'), 'appyhay', 'Passing happy Should Return appyhay');
            fireunit.compare(englishToPigLatin.TranslateWord('question'), 'estionquay', 'Passing question Should Return estionquay');
            fireunit.compare(englishToPigLatin.TranslateWord('star'), 'arstay', 'Passing star Should Return arstay');
            fireunit.compare(englishToPigLatin.TranslateWord('three'), 'eethray', 'Passing three Should Return eethray');
    
            //Vowel Words
            fireunit.compare(englishToPigLatin.TranslateWord('apple'), 'appleay', 'apple Should Return appleay');
            fireunit.compare(englishToPigLatin.TranslateWord('elijah'), 'elijahay', 'elijah Should Return elijahay');
            fireunit.compare(englishToPigLatin.TranslateWord('igloo'), 'iglooay', 'igloo Should Return iglooay');
            fireunit.compare(englishToPigLatin.TranslateWord('octopus'), 'octopusay', 'octopus Should Return octopusay');
            fireunit.compare(englishToPigLatin.TranslateWord('umbrella'), 'umbrellaay', 'umbrella Should Return umbrellaay');
    
            //Sentences
            fireunit.compare(englishToPigLatin.Translate('hello'), 'ellohay', "Passing 'hello' Should Return 'elloh'");
            fireunit.compare(englishToPigLatin.Translate('hello world'), 'ellohay orldway', "Passing 'hello world' Should Return 'elloh orldw'");
            fireunit.compare(englishToPigLatin.Translate('hello world!'), 'ellohay orld!way', "Passing 'hello world!' Should Return 'ellow orld!w'");
            fireunit.compare(englishToPigLatin.Translate('Hello World'), 'elloHay orldWay', "Passing 'Hello World' Should Return 'elloH orldW'");
            fireunit.compare(englishToPigLatin.Translate('Hello World!'), 'elloHay orld!Way', "Passing 'Hello World!' Should Return 'elloH orld!W'");
    
            // Wait for asynchronous operation.
            setTimeout(function() {
                // Finish test
                fireunit.testDone();
            }, 1000);
        </script>
    </head>
    <body />
    </html>

    If we run the webpage inside of Firefox, we don’t see anything from the browser window, but if we open Firebug and click the “Tests” tab, then we can see the output of the 20 tests.

    FireUnit

    One of the other nice features of FireUnit is that its compare assertion will actually show the difference of the two values instead of just saying they are the same or not. Here is an example of the output from a failing compare…

    FireUnitCompare

    The output is pretty impressive, but what if you already have a lot of existing QUnit Unit Tests or what if you would also like to have some sort of User Interface to your test page. Well, the nice thing about FireUnit is that you can integrate it into QUnit! By adding several lines of code we can have the output of our QUnit tests render to the FireUnit Add-on as well!

    The following is a set of QUnit Unit Tests with 4 lines of code near the end that registers the output with FireUnit as well.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
        <title>English To Pig Latin QUnit Tests</title>
        <link rel="stylesheet" href="http://jqueryjs.googlecode.com/svn/trunk/qunit/testsuite.css" type="text/css" media="screen" />
        <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
        <script type="text/javascript" src="http://jqueryjs.googlecode.com/svn/trunk/qunit/testrunner.js"></script>
        <script type="text/javascript" src="PigLatinBad.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
    
                module("Pig Latin");
    
                var englishToPigLatin = new EnglishToPigLatin();
    
                test('Invalid Arguments', function() {
                    equals(englishToPigLatin.TranslateWord(null), '', 'Passing Null Should Return Blank');
                    equals(englishToPigLatin.TranslateWord(''), '', 'Passing Blank Should Return Blank');
                    equals(englishToPigLatin.TranslateWord('1234567890'), '', 'Passing 1234567890 Should Return Blank');
                    equals(englishToPigLatin.TranslateWord('~!@#$%^&*()_+'), '', 'Passing ~!@#$%^&*()_+ Should Return Blank');
                });
    
                test('Consonant Words', function() {
                    equals(englishToPigLatin.TranslateWord('beast'), 'eastbay', 'Passing Beast Should Return Eastbay');
                    equals(englishToPigLatin.TranslateWord('dough'), 'oughday', 'Passing Dough Should Return Oughday');
                    equals(englishToPigLatin.TranslateWord('happy'), 'appyhay', 'Passing happy Should Return appyhay');
                    equals(englishToPigLatin.TranslateWord('question'), 'estionquay', 'Passing question Should Return estionquay');
                    equals(englishToPigLatin.TranslateWord('star'), 'arstay', 'Passing star Should Return arstay');
                    equals(englishToPigLatin.TranslateWord('three'), 'eethray', 'Passing three Should Return eethray');
                });
    
                test('Vowel Words', function() {
                    equals(englishToPigLatin.TranslateWord('apple'), 'appleay', 'apple Should Return appleay');
                    equals(englishToPigLatin.TranslateWord('elijah'), 'elijahay', 'elijah Should Return elijahay');
                    equals(englishToPigLatin.TranslateWord('igloo'), 'iglooay', 'igloo Should Return iglooay');
                    equals(englishToPigLatin.TranslateWord('octopus'), 'octopusay', 'octopus Should Return octopusay');
                    equals(englishToPigLatin.TranslateWord('umbrella'), 'umbrellaay', 'umbrella Should Return umbrellaay');
                });
    
                test('Sentences', function() {
                    equals(englishToPigLatin.Translate('hello'), 'ellohay', "Passing 'hello' Should Return 'elloh'");
                    equals(englishToPigLatin.Translate('hello world'), 'ellohay orldway', "Passing 'hello world' Should Return 'elloh orldw'");
                    equals(englishToPigLatin.Translate('hello world!'), 'ellohay orld!way', "Passing 'hello world!' Should Return 'ellow orld!w'");
                    equals(englishToPigLatin.Translate('Hello World'), 'elloHay orldWay', "Passing 'Hello World' Should Return 'elloH orldW'");
                    equals(englishToPigLatin.Translate('Hello World!'), 'elloHay orld!Way', "Passing 'Hello World!' Should Return 'elloH orld!W'");
                });
    
                if (typeof fireunit === "object") {
                    QUnit.log = fireunit.ok;
                    QUnit.done = fireunit.testDone;
                }
    
            });
        </script>
    </head>
    <body>
        <h1>English To Pig Latin QUnit Tests</h1>
        <h2 id="banner"></h2>
        <h2 id="userAgent"></h2>
        <ol id="tests"></ol>
        <div id="main"></div>
    </body>
    </html>
    
    QUnitWithFireUnit 

    Now, not only do we have a User Interface on the webpage, but we also have the tests running in Firebug.

    For more information about FireUnit you can check out a post by Jonn Resig and it’s Wiki on GitHub. And if you are interested in QUnit, there is a nice overview on the jQuery webiste.

    Sunday, September 20, 2009

    Using StructureMap with ASP.NET MVC & MVC Contrib

    I’ve found myself using the MVC Contrib project more and more lately. There are tons of golden framework nuggets just waiting to be used.

    I recently integrated StructureMap into the my current ASP.NET MVC framework using MVC Contrib. The reason I decided to write this post is because most of the resources I found on the internet appeared to be a little out of date and used deprecated StructureMap APIs. So, here it goes…

    Note: The following examples are using StructureMap v2.5.3 & ASP.NET MVC v2 Preview 1 & MVC Contrib MVC2 Branch code bits. You may find minor differences in API &| syntax if you are using a different version.

    First lets investigate why StructureMap is necessary in the first place. You can find some good blog posts by Jeremy D. Miller about the basics of the Dependency Injection Pattern and using an IOC tool.

    In order to facilitate mocking and decouple our application we pass an interface of our service into our controller instead of a concrete class. The default controller factory that ASP.NET MVC uses requires a default constructor to be present, but we are going to define our own Controller Factory later in this post using one of the MVC Contrib classes.

    Note: There is actually a really good screencast with @robconery and @jeremydmiller about using StructureMap in ASP.NET MVC. There were several “Aha!” moments for me as I watched it. The StructureMap API has changed slightly since the screencast, but I will show the updated syntax in the following of this post.

    The following is a typical ContactController class that will house the Index, Details, Create, Edit, and Delete actions. You will notice that instead of having a default constructor, I have an overloaded contructor and am passing in an interface to my service. I will wire up StructureMap to handle passing in the appropriate object later in this post.

    public partial class ContactController : Controller
    {
        private IContactService service;
    
        public ContactController(IContactService service)
        {
            this.service = service;
        }
    }    

    The wiring part, happens typically in the Application_Start event from the Global.asax.cs file. In addition to Registering your MVC routes (which should have already been wired up when you created your MVC application) you need to both configure StuctureMap to know what concrete classes map to what interfaces as well as tell MVC to use StructureMap to create its controllers.

    public class Global : HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes(RouteTable.Routes);
    
            Bootstrapper.ConfigureStructureMap();
            ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
        }
    }

    I am going to attempt and explain the above code snippet line by line, so lets start with the Bootstrapper.ConfigureStructureMap() and then we will discuss the StructureMapControllerFactory().

    After everything is said and done, the important part of StructureMap is that it knows what interfaces should map to what concrete types so that it can inject the appropriate instances at runtime. This is where the Bootstrapper.ConfigureStructureMap() comes into play.

    public static class Bootstrapper 
    {
        public static void ConfigureStructureMap()
        {
            ObjectFactory.Initialize(x => x.AddRegistry(new MyApplicationRegistry()));            
        }
    }
    
    public class MyApplicationRegistry : Registry
    {
        public MyApplicationRegistry()
        {
            Scan(assemblyScanner =>
            {
                assemblyScanner.TheCallingAssembly();
                assemblyScanner.WithDefaultConventions();
            });
        }
    }

    The above code is initializing StructureMap with the MyApplicationRegistry that contains the rules for the interface & concrete type mappings. You may be wondering, “But I don’t see where IContactService is mapped to ContactService” and that is a very good question. The answer is that StuctureMap takes the Convention Over Configuration approach and tries to take some educational guesses based on a set of default naming conventions.

    Lets say that your configuration isn’t following standard naming conventions. Can you still use StructureMap? Well, of course you can :) You have full control over the mappings and can set them up however you wish. The following is an example of me manually doing the mapping instead of using the default naming conventions. The Bootstrapper remains the same, so I only will show the code that is different below…

    public class MyApplicationRegistry : Registry
    {
        public MyApplicationRegistry()
        {
            ForRequestedType<IContactService>().TheDefaultIsConcreteType<ContactService>();
            ForRequestedType<IValidationRunner>().TheDefaultIsConcreteType<ValidationRunner>();
        }
    }

    Now lets focus on the StructureMapControllerFactory that we saw after we Configured StructureMap from the Global.asax. The StructureMapControllerFactory class that I am instantiating actually comes with the MVC Contrib project.  The contents of this class isn’t really all that complicated, but its one less thing you have to write by hand. The following is an example of a oversimplified implementation of the StructureMapControllerFactory that you could write yourself…

    public class StructureMapControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return ObjectFactory.GetInstance(controllerType) as IController;
        }
    }

    Since we separated our dependencies and used StructureMap for injection our application is now loosely coupled and our ability to Unit Test more areas has increased.

    Stay tuned for a new series where I will upgrade a standard ASP.NET MVC project to ASP.NET MVC 2 and then integrate StructureMap, Moq, MbUnit, and suite of Unit Tests.

    Friday, September 18, 2009

    ASP.NET AJAX Add-ons (FireAtlas & FireCookie) for Firefox's Firebug

    Today’s screencast is the 4th in a series of developer Firefox Extensions. You can view my previous 3 short Screenr screencasts here…

    For those of you that do ASP.NET or ASP.NET AJAX development, then the following Firebug Add-ons might be of interest to you.

    FireAtlas is a tool that enables you to view the PageRequestManager events, trace WebService calls, inspect Partial Updates, and view any installed application components. You can actually try out some samples pages to exercise most of the functionality of this Add-on, but I will be viewing the twitter scheduler application TwtMstr (developed by @wbm) to demonstrate some of the features in my screencast.

    FireCookie is another useful tool that allows you to view any cookies that are relevant for the current web page. This can be handy for an ASP.NET developer to inspect the .ASPXROLES, .ASPXAUTH, or ASP.NET_SessionId values that are common for most ASP.NET applications.

     

    Yet again, I hope this was beneficial to you. If you enjoyed the presentation I would appreciate either a comment to this blog &| a tweet about it to share with others.

    "#ASPNET #AJAX Add-ons (FireAtlas & FireCookie) for #Firefox's #Firebug" by @elijahmanor #tech #nettuts #screencast http://j.mp/111ZQO

    Also, if you have any suggestions that you have to help become a better presenter I would appreciate that as well. If you have a minute, please add a comment with your thoughts.