CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

July 2006 - Posts

  • I could code that, well maybe not

    After getting my toddler to bed, I've been sitting on the living room couch writing a real blog post and watching a Tivo'ed episode of Stargate SG-1.  The brilliant scientist types are concocting a scheme to write a computer virus to disable the Stargate system for the bad guys, or something like that.  I happened to look up and notice the two characters on the show were writing snippets of code on a whiteboard to open a FileStream object in what looks like C#. 

    I don't know about you, but I don't think I could write a C# program in 24 hours to reprogram an advanced alien technology.  Heck, I spent a good chunk of the day last Thursday just trying to get a web service proxy and web service to work with X509 certificate security.  I feel inadequate.

    Of course, if we could just make the right abstracted DSL for the Stargate protocol...

     

    Ok, I'm fine with the Stargate shows and Battlestar Galactica, but explain to me again why Firefly was a commercial flop and these shows are going strong?

     

     

     

     

  • Karma

    If you're as big a fan of My Name is Earl as I am, you'll understand me when I say that Karma is punishing me today for the ASP code that I wrote circa 1998. I've been messing with some legacy ASP code that wasn't working in one environment, and had to resort to this

    On Error Resume Next
    ' Do stuff
    If err.Number <> 0 Then
      Response.Write "Number = " & err.Number & "<p>"
      Response.Write "Description = " & err.Description & "<p>"
      Response.Write "Source = " & err.Source
      err.Clear
    End 
    
    

    I've been bad mouthing ASP.Net lately at work and in user groups (and RoR is just so shiny and new), but give me ASP.Net over spaghetti code ASP and VBScript any day of the week.

  • Sometimes Dilbert just makes me sad

    It's been awhile since I've been in this position, but the strip still hurts.  At least our deadlines kinda make since, it's the date when sales promised a feature to a client without asking us first.

  • Chiefs sign Law, Hope springs eternal (Way Off Topic)

    http://cbs.sportsline.com/nfl/story/9568425/rss

    Ok, I'm a happy, lifelong Chiefs fan at the moment.  Don't even think about raining on my parade by putting a comment here about how KC's offense is a bunch of geriatrics or how the defense has been awful since Derrick Thomas passed away.

  • An infallible mechanism to measure your growth as a developer

    Unfortunately, I think the best barometer to measure your growth as a developer is looking at your old code and cringing.  This morning I needed a little enhancement to a web page, and rather than writing something new or looking for something to download, I went and pulled out an old script I'd written 4+ years ago.  It's perfectly functional and worked on the first try, but I made the mistake of looking closely at the code and almost wanted to puke.

    I've almost always gone through a wave of "man, I wish I'd done that differently" headshaking after significant projects.  I've never been able to look at a completed system six months later and not see ways that it could have been built better or simpler.  If your code from a year ago looks good to you, you might just have peaked as a developer.

  • Do you really need a CS degree to be a developer?

    I was reading this post on starting a new software project this morning and basically nodding along with everything the writer said (with an emphatic nod at point #1), until I hit this part at the bottom:

    Do not hire people without Angel [A] Computer Science education.

    So, back to the question in the title, do you really need a CS degree to be a good developer? I obviously hope not, since my education and early career background is Mechanical Engineering.  I'm admittedly weak in terms of some low level concepts, but I've never felt that I wasn't as effective as the CS grads I've worked with.  I'm certainly not Jeffrey Richter or Raymond Chen, but I do know how to build maintainable code.  I certainly have no business writing compilers or embedded processor code.  But in the world of business applications where most of us live, my engineering background is actually an advantage because engineering in practice is largely an exercise in modeling the real world in abstractions.  I'd even go farther to say that I've never observed a general trend of the Computer Science graduates I've worked with being any stronger than the rest of us.  <RANT>Actually, the irritating thing for me is working with code written by a CS major that obsesses over low level garbage collection and CLR mechanics while writing unmaintainable code with a stratospheric Cyclomatic Complexity number without any unit tests.</RANT>

    Just off of the top of my head, many of the strongest, most effective developers I've worked with have had degrees in:

    • Music (surprisingly common, but it's understandable)
    • Physics
    • Engineering of all types.  Engineering is dull with a capital D.  Lots of us wander into writing code if given half a chance.
    • English (!)
    • Theoretical Mathematics

    Of course, the common trait of *all* the strong developers I've worked with is a passion and enthusiasm for software development.  I'm not discounting the CS major, and certainly not the knowledge behind it, but I'd worry a lot more about enthusiasm, passion, discipline, collaboration skills, and even raw intelligence first.

    And don't even get me started about certifications...

  • Create a Testing DSL with FitNesse and Selenium (Part 2)

    In my previous post, in the context of some large scale automated tests for our new "Bundle" processing subsystem, I introduced my best friend in the whole wide world of test automation, the FitNesse DoFixture.  So far I'm pretty pleased with Selenium web testing from within FitNesse tests because it keeps all of our acceptance tests together in one place, simplifying our continuous integration scripts and reporting.  I also think that the FitNesse wrapper gives us a lot more flexibility in the grammars we can use to model and execute the system than Selenium alone.  The main reasons I like running Selenium from within FitNesse is the ability to create self-contained tests that setup their own data before the web page interaction and the ability to check the state of the system after the web page interaction.  The key to effective integration testing is easy to use mechanisms for setting up the application state and verifying the application state.  This post is a grab bag of the FitNesse idioms we use to set up inputs and check outputs.

    Getting Data Into Your System

    For pushing data into the system we primarily use subclasses of the ColumnFixture.  Setting up data isn't its stated purpose, but it's very handy for this nonetheless.  Here's an example of a ColumnFixture test table.

    	!|SomeColumnFixture|
    	| IncomeTaxRate | YearlyIncome | Deductions | OwedTaxes() |
    	| .10           | 100000       | 10000      | 9000        |
    	| .5            | 100000       | 0          | 5000        |
    

    The code for the SomeColumnFixture might look something like this:

        public class SomeColumnFixture : ColumnFixture

        {

            private decimal _incomeTaxRate;

            private decimal _yearlyIncome;

            private decimal _deductions = 0;

     

            public SomeColumnFixture()

            {

            }

     

            public decimal IncomeTaxRate

            {

                set { _incomeTaxRate = value; }

            }

     

            public decimal YearlyIncome

            {

                set { _yearlyIncome = value; }

            }

     

            public decimal Deductions

            {

                set { _deductions = value; }

            }

     

            public decimal OwedTaxes()

            {

                // Simply take the values previously set in the instance fields

                // and return the result from the System Under Test (TaxCalculator)

                return TaxCalculator.CalculateTaxTotal(_incomeTaxRate, _yearlyIncome, _deductions);

            }

    When a ColumnFixture starts, it first scans the header row. A header without parentheses directs ColumnFixture to call a {set;} property on the ColumnFixture class when that cell is processed. A header with parentheses directs the ColumnFixture to call a method and compare the results with the contents of that cell.  It's effectively the same thing as calling Assert.AreEquals(expected, actual) in NUnit.  In the example above, as SomeColumnFixture parses the first body row of the test table, it will these calls on itself with reflection:

    1. IncomeTaxRate = .10
    2. YearlyIncome = 100000
    3. Deductions = 10000
    4. Grabs the return value from OwedTaxes()

    So that's the basic mechanism of a ColumnFixture.  Before I jump into using the ColumnFixture to load data, there's a couple of virtual "hook" methods in the ColumnFixture abstract class that you need to be aware of:

            public virtual void Reset() {

                // about to process first cell of row

            }

     

            public virtual void Execute() {

                // about to process first method call of row

            }

    Now, onto loading data.  We roughly use a ColumnFixture per domain model class or database table.  The code below is a slightly obfuscated version of the Fixture we use to load users into the system during the SetUp of a FitNesse test.  We have several user interface tests where we need to filter the User table for dropdown lists or security checks.  With the UserDefinitionFixture our tester can quickly setup the system with a known set of users with the desired characteristics and preferences.  

        public class UserDefinitionFixture : ColumnFixture

        {

            // IDomainSource is a Repository class that wraps access to NHibernate

            private readonly IDomainSource _source;

            private User _user;

     

            public UserDefinitionFixture(IDomainSource source)

            {

                SessionSource.Reset();

                _source = source;

            }

     

            public override void Reset()

            {

                // Create a new User object and set some basic defaults

                // My boss & I are both fans of Roger Zelazny's Amber books

                // if you are wondering where the weird names come from

                _user = new User();

                _user.Address1 = "Kolvir Street";

                _user.Address2 = "Suite 100";

                _user.FirstName = "Jeremy (Prince)";

                _user.LastName = "Miller";

                _user.City= "Amber";

                _user.StateCode = "TX";

                _user.PostalCode = "77777";

                _user.Phone = "123-456-7890";

                _user.Email = "Corwin@amber.com";

                _user.Fax = "Tarot 9675";

                _user.CountryCode = "US";

                _user.Status = "AUTH";

                _user.SerialNumber = Guid.NewGuid().ToString();

            }

     

            // 1. Delete any existing User's with the same Id

            // 2. Persist the new User object with NHibernate

            public override void Execute()

            {

                string sql = string.Format("delete from users where id = '{0}'", _user.Id);

                IDataSession session = (IDataSession) ObjectFactory.GetInstance(typeof (IDataSession));

                session.ExecuteSql(sql);

     

                _source.Save(_user);

            }

     

            public string Id

            {

                set

                {

                    _user.Id = value;

                }

            }

     

            public string FirstName

            {

                set

                {

                    _user.FirstName = value;

                }

            }

     

            public string LastName

            {

                set

                {

                    _user.LastName = value;

                }

            }

     

            public string CompanyId

            {

                set

                {

                    FindByKeyQuery query = new FindByKeyQuery(typeof (Company), value);

                    IList list = _source.Query(query);

                    Company company = (Company) list[0];

     

                    _user.Company = company;

                }

            }

     

            public string City

            {

                set

                {

                    _user.City = value;

                }

            }

     

            public string StateCode

            {

                set

                {

                    _user.StateCode = value;

                }

            }

    Here's a test table for that fixture that will create three new users.

    	!|UserDefinitionFixture|
    	|Id        |CompanyId     |
    	|User1     |C0001         |
    	|User2     |C0002         |
    	|User3     |C0003         |
    

    So what's going on here?  Everytime this fixture hits a new row it creates a new user object with a set of default values.  When it parses the Id column it assigns a user id.  When it parses the CompanyId column it looks up a previously configured Company object and makes that the parent of the new User object.  At the end of the row the UserDefinitionFixture will call its Execute() method that will first delete any existing User row in the database with that id and then call IDomainSource (NHibernate wrapper) to persist the new User object.  You'll notice that my test table didn't include the state or city columns.  It's a good thing to define default values so your tester does not have to specify a lot of "noise" data.  Our User table has a couple of properties that control access to certain features in the application.  When we're testing that subsystem we use a UserDefinitionFixture table with only the pertinent columns.

    You can adapt this strategy quite easily to simple "Insert" database statements.  In this case the setter properties just put data into a parameter of the sql command.  You just execute the sql statement in the Execute() method.

    Dealing with Surrogate Keys

    There's a little bit of fuss right now in the Ruby on Rails world about whether or not RoR's ActiveRecord subsystem needs to be adapted to work with composite database keys*.  There's a definite bias in favor of surrogate keys that I've come to agree with.  It's great for persistence, but it does make some automated testing of long running workflows more difficult.  The surrogate key is usually defined by the database itself the first time an object is persisted. In other words, we don't know the value of the new id at the time we write the tests.  We've adopted a practice of identifying domain objects in FitNesse tests by a testing alias.  In our new Bundle subsystem we simply put a hashtable on a commonly used fixture to store a mapping of the testing alias to the sequential bundle id.

            private static Hashtable _bundleIdHash = new Hashtable();

            public static long GetBundleId(string bundleName)

            {

                return (long) _bundleIdHash[bundleName];

            }

     

            public static void StoreBundleId(string bundleName, long controlId)

            {

                _bundleIdHash.Add(bundleName, controlId);

            }

    When we define a new Bundle we simply give it an alias and never refer to the bundle id.

    	!|BundleDefinitionFixture|
    	|BundleName        | Communication Type |
    	|TestBundle1       | Fax                |
    	|TestBundle2       | Email              |
    	
    	In later fixtures we can refer to the named bundle
    	
    	!|BundleServiceFixture|
    	|Check Bundle State for | TestBundle1 |
    	| Status()      |
    	| Approved      |
    

     

    Checking the State of the System - ColumnFixture

    In the last post I showed how to use DoFixture grammars to check the state of a single value in the system.  That's really not adequate for the majority of cases.  In our new Bundle subsystem we have some processes that can change several properties of a single Bundle object.  I like to use a ColumnFixture to declaratively state the expected state of a Bundle object.  We use a fixture called BundleVerificationFixture to verify the expected state of a Bundle.  One of the very cool things about a DoFixture is that it allows you to nest other Fixtures within the DoFixture.  In this case we have a grammar on our DoFixture that will start and return a BundleVerificationFixture to verify the state of a given Bundle.

            public Fixture BundleState(string bundleName)

            {

                SessionSource.Reset();

     

                // The findNamedBundle first finds the surrogate id

                // value for the test alias "bundleName,"

                // then retrieves the Bundle object from NHibernate

                Bundle bundle = findNamedBundle(bundleName);

                return new BundleVerificationFixture(bundle);

            }

    The BundleVerificationFixture itself is very simple. All we have to do is make a method (and yes, it has to be a method not a getter) for each property of the Bundle object that we want to verify.

            public string Status()

            {

                return _bundle.Status.ToString();

            }

     

            public string CommunicationType()

            {

                return _bundle.CommunicationType.ToString();

            }

    The table usage is:

    	!|BundleServiceFixture|
    	|Bundle State | TestBundle1 |
    	|Status()     | CommunicationType()   |
    	|Approved     | Fax                   |
    

    Checking the State of the System - RowFixture

    There's always a one to many or a many to many relationship lurking somewhere in almost any enterprise application.  FitNesse provides a really slick mechanism for verifying a set of data, the RowFixture.  To implement a RowFixture, you simply need to subclass RowFixture and override two methods.  The rest is reflection magic (notice the trend here in FitNesse world?).

            public abstract object[] Query(); // get rows to be compared

            public abstract Type GetTargetClass(); // get expected type of row

    The challenging part is the Query() method.  Where does the data come from?  Typically this data is produced by some action that has taken place in the test before the RowFixture runs. In the dark, dark days before the DoFixture we would pass a lot of data around in static members from fixture to fixture. With the DoFixture, we generally wrap the querying into a DoFixture grammar. 

    Here's an example from a previous life.  You're building a scheduling engine to determine the build order of factory orders.  One of the outputs of the engine is a listing of what parts are needed, in what quantity, at a factory line at the beginning of a shift.  First we can build a very quick RowFixture to check an array of OrderDetail objects.

        public class OrderDetail

        {

            private string _partNumber;

            private long _quantity;

     

            public string PartNumber

            {

                get { return _partNumber; }

                set { _partNumber = value; }

            }

     

            public long Quantity

            {

                get { return _quantity; }

                set { _quantity = value; }

            }

        }

     

        public class OrderDetailFixture : RowFixture

        {

            private readonly OrderDetail[] _details;

     

            public OrderDetailFixture(OrderDetail[] details)

            {

                _details = details;

            }

     

            public override object[] Query()

            {

                return _details;

            }

     

            // How do you like the Java-ism in the port?

            public override Type GetTargetClass()

            {

                return typeof (OrderDetail);

            }

        }

    The OrderDetailFixture needs something else to push its data to it.  That would be our SchedulingEngineFixture.

        public class SchedulingEngineFixture : DoFixture

        {

            public Fixture TheOrderDetailsForLineDuringShiftAre(string lineNumber, int shiftNumber)

            {

                OrderDetail[] details = findOrderDetails(lineNumber, shiftNumber);

                return new OrderDetailFixture(details);

            }

        }

    A sample test table would look like this:

    	!|SchedulingEngineFixture|
    	|The Order Details For Line | Line1 | During Shift | 2 | Are |
    	| PartNumber | Quantity |
    	| 10X34      | 120      |
    	| 2TUER      | 35       |
    

    The RowFixture allows you to declaratively state the expectation of a set.  When it's executed, the RowFixture will add unexpected values to the table as a test failure and show you the values that weren't present in the actual set.  The RowFixture really becomes powerful when it's wrapped in a DoFixture to provide query parameters.

     

     

    * This isn't just a limitation of ActiveRecord, we've had some difficulties with NHibernate and composite keys.  My opinion on that issue is to just go and add a new surrogate key column on the end of legacy tables and make it a unique constraint.  You can leave the composite primary key alone, but I'd guess that every O/R mapping tool works better against a single key anyway. 

  • Create a Testing DSL with FitNesse and Selenium (Part 1)

    My team uses FitNesse extensively to create automated acceptance tests for our systems.  Recently we've added Selenium RC running from within FitNesse to our toolbox.  There's a lot of buzz lately over the creation of Domain Specific Languages (DSL), driven in no small part to create a syntax for the application code that is readable by the business partners and testers.  We accomplish the same goal (or at least try to) by using FitNesse fixtures to effectively create a DSL for our applications that our tester can use to specify and verify the expected behavior of the system.  FitNesse is both the "language" parser and a reporting framework that can already be plugged into NAnt and CC.Net, so there's no real need to create custom interpreters.  Take that you Ruby cool kids with your "missing_method" metaprogramming magic!

    Most of my last week and a half has been spent building the "Mother of all Automated Tests."  The system under test was basically a new messaging workflow between our company and a partner company for something that we call a "Bundle."  All told, the entire Bundle pipeline includes:

    • A web application on our side to start the  Bundle workflow and approve or reject work from our partner
    • An extension to our messaging broker component that runs as a polling windows service
    • A web service, that we're building, installed on server at our partner's that will receive notifications of a new Bundle for them to process
    • A web service on our side that will receive a pair of notifications from the partner, including the finished product.  This web service enforces a wide range of business rules

    The communication pipeline is fairly complex, there isn't a user interface for much of it, the web service messages are non-trivial, and the validation rules are extensive.  Creating a FitNesse grammar for us and our tester to simulate the communication has been a lifesaver.  Using our DSL we can quickly throw a lot of different scenarios at the system in a repeatable manner.

    The DoFixture is the Lynchpin

    FIT (and FitNesse) has always had the ability to express tests as declarative tables.  It works great when you can stay within the lines of x number of inputs leads to y outputs, but it breaks down for more complex scenarios like, well, basically anything in an enterprise application.  It's also a mess to maintain state between fixture tables because all you have are static members.  All of that changed because now we have the DoFixture.  I think I've said before in this blog that I didn't particularly care much for FIT style testing until we got the DoFixture from Rick Mugridge's FitLibrary extension. 

    The DoFixture allows us to create custom textual languages to express tests.  In other words, jagged tables.  I'll leave it for a later post, but the DoFixture allows us to nest other fixture tables to do declarative assertions.  Think of the DoFixture as an interpreter that enables us to quickly create grammars without getting bogged down by writing our own parsing and reporting functionality.  Here's an example straight out of our tests on the Bundle workflow.

        public class CreateBundleScreenFixture : DoFixture

        {

            public void CreateBundleFromToAsAWithInvoiceTotalWithAttachment(

                string senderId,

                string receiverId,

                string communicationType,

                decimal invoiceTotal,

                string fileName)

            {

                // call into your application's service layer with the inputs above

            }

        }

    That's the Fixture code, it's nothing special, just a method. Let's move onto the representation in a FitNesse table. In FitNesse's particular version of Wiki markup, "!" is a directive to start a new table. New table cells are started just by delimiting the contents with a "|" character. Just to avoid some unpleasantness, always remember to close each line with a pipe bar and no trailing spaces.  I'm going to make all of the FitNesse sample in Wiki text because that's what you'll be editing (and the blog engine will screw up the table formatting).

    	!|CreateBundleScreenFixture|
    	| Create Bundle From | Sender1 | To | Receiver1 | 
    as a | Fax | With Invoice Total | 1018.23 | 
    With Attachment | Invoice1.pdf |
    

    The DoFixture parses this command by treating the table row as an array of cells.  Starting with the first cell, DoFixture iterates through every other cell, concatenates the text together, and removes all of the white space.  The DoFixture uses this concatenated string as the method name, which is located through reflection (lots and lots of reflection).  Back to the other cells that got skipped over, DoFixture assumes that these cells are the arguments to the method in order.  The DoFixture is able to determine the type of the argument from the method signature and coerce the types.  In this case the DoFixture automatically converts the string "1018.23" into a decimal type before pushing it into the invoiceTotal argument of the CreateBundleFromToAsAWithInvoiceTotalWithAttachment() method.  FitNesse itself in .Net handles all of the normal primitive types, including DateTime values.  In an annoying oversight, the .Net version misses enumeration types.  If anybody is interested, I can show some code to plug into FitNesse to modify the way FitNesse parses and handles any particular type.

    So that's how you create an action in a DoFixture.  FitNesse will of course fail the test if the action blows up with an exception, but you also need to make assertions about the outcome of the action.  The simplest thing to do is create a method that returns a Boolean.  The DoFixture will automatically treat any method with a Boolean return value as an assertion.  Without any arguments, that might look like:

            public bool TheBundleWasCreatedSuccessfully()

            {

                return _lastBundleSucceeded;

            }

    	!|CreateBundleScreenFixture|
    	| Create Bundle From | Sender1 | To | 
    Receiver1 | as a | Fax | With Invoice Total | 
    1018.23 | With Attachment | Invoice1.pdf |
    	| The Bundle Was Created Successfully |
    

    Fancier assertions can be made by using the Check keyword.  Let's add some grammars to test the Status of the newly created Bundle object.

            public void AliasTheLastBundleAs(string bundleName)

            {

                // store the Id of the last Bundle created in the FitNesse fixture

                // as bundleName

            }

     

            public string TheBundleStatusOfIs(string bundleName)

            {

                // look up the Status field from the Bundle aliased

                // as [bundleName] and return

            }

    	!|CreateBundleScreenFixture|
    	| Create Bundle From | Sender1 | To | Receiver1 | 
    as a | Fax | With Invoice Total | 1018.23 | 
    With Attachment | Invoice1.pdf |
    	| The Bundle Was Created Successfully |
    	| Alias the Last Bundle As | TestBundle1 |
    	| Check | The Bundle Status of | TestBundle1 | Is | New |
    

    By starting the test row with "Check," I've directed DoFixture to assert that the value of the TheBundleStatusOfIs("TestBundle1") method is the value in the last cell.  When the test is executed, FitNesse will color the last cell green if it succeeds, or red with an NUnit-like "expected blah, actual blah" text description.  One of the best advantages to FitNesse testing is the visceral red/green output.  It's usually pretty easy to spot the test failures (diagnosing the cause, is alas, as difficult as always). 

    More complex assertions usually call for a nested Fixture table.  I'll demonstrate a couple examples in later sections.  If you can't already guess, I love the DoFixture.

    Environment Settings

    At some point FitNesse and Selenium have to know some environment settings.  You can accomplish this through the normal configuration techniques, but I've started to put a lot of this type of information in the FitNesse tests themselves.  FitNesse allows for a "SetUp" test page that will be included inside each test page in a test suite.  I used a little DoFixture that looks something like this:

        public class MySystemEnvironmentFixture : DoFixture

        {

            // Yes, I do realize that I'm using a public static field

            // It's okay -- in this context anyway

            public static string ApplicationRoot = "http://localhost/MyApp/";

            public static string WebServer = "http://localhost";

            public static string BrowserName = "*firefox";

     

            private static DefaultSelenium _selenium;

     

     

            public void TheWebServerIs(string webServer)

            {

                WebServer = webServer;

            }

     

            public void TheApplicationIsRootedAt(string root)

            {

                ApplicationRoot = root;

            }

     

            public void TheBrowserIs(string browserName)

            {

                BrowserName = browserName;

            }

        }

    Inside the SetUp page I have a table like this:

    	!|MySystemEnvironmentFixture|
    	| The Web Server Is            | http://MyTestServer/                |
    	| The Application Is Rooted At | http://MyTestServer/TheTestingRoot/ |
    	| The Browser Is               | *iexplore                           |
    

    In one place, I can quickly shift the FitNesse fixtures from pointing from a local installation on my workstation, to the development servers, or finally to the testing servers.  If you'll notice the third line, I can also switch the browser engine that Selenium is using (IE, Firefox, Opera, etc.).  That's awfully important in the age of AJAX/Web 2.0 tricks with multiple browsers.

    Integrating Selenium into a DoFixture

    Finally, let's pull Selenium into the mix to drive the web pages.  While you can use Selenium with its own FIT-like driver, or though NUnit, I like running Selenium from within FitNesse for acceptance tests.  I like this approach because we get a unified reporting and execution infrastructure for both UI and Service Layer tests.  Plus, and this cannot be underestimated, I can use regular FitNesse fixtures to setup and verify application state before and after the Selenium execution in a single self-contained test.

    We're using the .Net driver for Selenium RC.  I wrote a brief introduction to using Selenium RC from .Net that explains the basic mechanisms.

    The first thing to do is create a new Selenium session and make it accessible to all of the Fixture's in a test.  I'm working on an assumption that we will normally write a separate FitNesse fixture for each non-trivial screen, and share the Selenium driver object in a static member somewhere in memory.  I'm going to start by adding some infrastructure to the MySystemEnvironmentFixture just to provide access to a DefaultSelenium object.

            // Create a new Selenium session

            private static void resetSelenium()

            {

                // Use the ApplicationRoot and BrowserName fields

                _selenium = new DefaultSelenium("localhost", 4444, BrowserName, ApplicationRoot);

                _selenium.Start();

            }

     

            // Provide access to the currently executing Selenium session

            // to other screen fixtures

            public static DefaultSelenium SeleniumDriver

            {

                get

                {

                    if (_selenium == null)

                    {

                        resetSelenium();

                    }

     

                    return _selenium;

                }

            }

     

            // Start a Selenium session, probably call this

            // in SetUp

            public void StartApplication()

            {

                resetSelenium();

            }

     

            // Shut down the Selenium session and free the

            // resources.  Either do this in TearDown or at

            // the end of every, single test.

            public void CloseApplication()

            {

                if (_selenium != null)

                {

                    _selenium.Stop();

                }

            }

    Since every call to "Start Application" will spawn a new browser instance, you should definitely remember to call "Close Application" at the end of each test or in the TearDown. Unless you don't mind out of memory exceptions on your build server;)

    	!| MySystemEnvironmentFixture |
    	| Start Application |
    	| Close Application |

    Now, let's create a little fixture to for a screen. In our Bundle workflow user interface we have a screen that displays all of the data about a single Bundle and has buttons to perform common actions on a Bundle like "Reject" or "Approve."

        public class BundleDetailsFixture

        {

            // Elements on the screen

            private const string STATUS_LABEL = "xpath=//*[@testid='status']";

            private const string APPROVE_BUTTON = "xpath=//*[@testid='status']";

            private const string REJECT_BUTTON = "xpath=//*[@testid='status']";

     

            private const string URL = "BundleDetails.aspx";

     

            DefaultSelenium _selenium;

     

            public BundleDetailsFixture()

            {

                // Go grab the current Selenium session object

                _selenium = MySystemEnvironmentFixture.SeleniumDriver;

            }

     

            public void OpenTheBrowserToBundle(string bundleName)

            {

                // Find the Id for the Bundle aliased as [bundleName]

                long bundleId = 0;

     

                string url = string.Format("{0}{1}?Id={2}", MySystemEnvironmentFixture.ApplicationRoot, URL, bundleId);

                _selenium.Open(url);

            }

     

            public string TheBundleStatusIs()

            {

                return _selenium.GetText(STATUS_LABEL);

            }

     

            public bool TheApproveButtonIsEnabled()

            {

                return _selenium.IsEditable(APPROVE_BUTTON);

            }

     

            public bool TheRejectButtonIsEnabled()

            {

                return _selenium.IsEditable(REJECT_BUTTON);

            }

     

     

            // Click the Reject button, and then click Cancel

            // on the confirmation popup box

            public void ClickTheRejectButtonAndCancel()

            {

                _selenium.ChooseCancelOnNextConfirmation();

                _selenium.Click(REJECT_BUTTON);

            }

     

            public void ClickTheApproveButton()

            {

                _selenium.Click(APPROVE_BUTTON);

            }

     

     

        }

    The simplest case is to call the service layer first to create a Bundle. Next we'll look at the Bundle Details screen to confirm the status of the Bundle, then approve the Bundle and check the status again.

    	
    	!|CreateBundleScreenFixture|
    	| Create Bundle From | Sender1 | To | Receiver1 | 
    as a | Fax | With Invoice Total | 1018.23 | 
    With Attachment | Invoice1.pdf |
    	| The Bundle Was Created Successfully |
    	| Alias the Last Bundle As | TestBundle1 |
    	
    	Now, call into the screen.  I'm assuming that the Selenium session was created in the FitNesse SetUp
    	By the way, you can quite happily mix prose with your testing tables
    	
    	!| BundleDetailsFixture |
    	| Open the Browser to Bundle | TestBundle1 |
    	| Check | The Bundle Status Is | New |
    	| The Approve Button Is Enabled |
    	| Click the Approve Button      |
    	| Check | The Bundle Status Is | Approved |
    

    That's pretty simple stuff.  Just about everything you need to check or manipulate on a web page is accessible from the DefaultSelenium object.  If it's not, you can send over your own Javascript to be evaluated in the browser.  I haven't bumped into anything that required that technique yet.  Selenium itself will largely take care of page transitions and postbacks for you.  If need be, you can direct Selenium to wait for a page transition with a timeout, or poll for a certain condition if you're doing heavy AJAX work.

    One of the other advantages for wrapping Selenium within FitNesse is to abstract away the page structure from the test writer.  The test writer, who may or may not have knowledge to the application's internals, can focus on the English language definition of the test and defer the xpath or id location of elements to the developers.  Because ASP.Net likes to munge up element id's of nested controls, we've adopted a convention of using an arbitrary "testid" attribute on an element to be the Selenium key for testing.  We can find an element with a testid anywhere on the page by using a locator like "xpath=//*[@testid='the test id']."

    The FitNesse wrapper gets really handy when you want to perform multiple steps in a single sentence, like repeatedly filling in a form in the same steps but with different input. Here's a cool example I haven't needed yet, but might soon. With most testing frameworks you have to setup an expectation for what to do when the next popup box shows up before you define the step that creates spawns the popup button. That's potentially confusing, and it certainly makes your testing harder to understand.  With the DoFixture we can write a better grammar for that case:

    	!| BundleDetailsFixture |
    	| Open the Browser to Bundle | TestBundle1 |
    	| Check | The Bundle Status Is | New |
    	| Click the Reject Button and Cancel |
    	| Check | The Bundle Status Is | New |
    

    Wrapping Up

    I wrote this in a hurry and probably missed quite a few details.  If you have any questions, or better yet, suggestions, feel free to leave a comment and I'll get to it quickly for once.

    It's just not that hard.  The hardest part of the giant end-to-end test was really the deployment scripts.  All I've shown here is the mechanics of simple cases.  In the next installment, I'll talk about the pattern I use to load data in FitNesse tests, and using nested Fixture's within a DoFixture to do more complex data entry and assertions.  I'll also try to get a post in on lessons learned and best practices, but I'm going to wait until the big end-to-end testing infrastructure is completely verified;)

  • If you want to learn about implementing Model View Presenter in ASP.Net, read this

    Billy McCafferty has published a very good introduction to the MVP in ASP.Net that dives into the mechanics of a lot of the common idioms in real life enterprise architecture.  I especially liked the example of enforcing user permissions on the view in the presenter class. 

     

    I mentioned a week or so back that I will be putting together an article on the Model View Presenter pattern sometime this month because I was getting a fair number of questions about the MVP pattern.  I'm still going to do it (the more the merrier on this topic), but I'm going to largely answer a lot of the specific questions about implementation with "go ready Billy's article on CodeProject."  Besides, I don't do a lot of heavy ASP.Net work anyway.

     

     

  • Slides from the StructureMap Talk Last Night at ADNUG

    The slide deck and sample code from my StructureMap talk last night is available from the ADNUG downloads page.  Thanks to Jeffrey Palermo for inviting me and everybody who attended.

    If you're using a different DI tool than StructureMap, we spent a lot of time talking about possible usages for DI tools in the wild that would apply to Castle or Spring.Net just as well.

    StructureMap itself is at http://structuremap.sourceforge.net.

    Here's some more resources on some of the design patterns we talked about last night:

    I think I'll get a sample application published here in the near-ish future, but I'm severely backed up on side projects right now.

  • One Weekend at "No Fluff," So Many Thoughts...

    I just spent a great, great weekend at the No Fluff, Just Stuff conference in Austin.  I would more or less characterize the conference as Drinking Ruby Koolaid from a Firehose.  Besides Ruby on Rails I sat in on talks about TDD, AJAX, SOA, building better teams, and coding in general.  Scott Bellware has his own, accurately named, write-up about the conference here:  A Long Weekend in Ruby Land.  Scott was uncharacteristically tame and non-controversial, so I'll take up the slack.  I walked away with a long laundry list of topics that struck a nerve with me during the weekend, most of which are going to be controversial and rightly so.  If I don't get flamed for something here, you're not paying attention.  Regardless, it's an interesting time to be a developer.  I think we're in the middle of one of those "uproot everything" phases like a couple of years ago when .Net was all shiny and new.

    Cool Quotes

    I'm going to butcher some of these, but these were the best lines I remember from the weekend.

    "When you pull a class off the shelf, what else is coming with it?" -- Stuart Holloway talking about using Dependency Injection.  I'm stealing that metaphor for my StructureMap talk tonight.

    "The Neck Bearded Unix Guy" -- The guy who completely dismisses any technique or technology you're enthusiastic about with the offhand dismissal "we already did that better in the 70's."  Neck Bearded Unix Guy is very likely to be an old Smalltalker.  Which is frankly fine with me, I can take that much better from a Smalltalker or LISP aficionado than I can from the COBOL troglodytes that dismiss any concept developed after the "IF/THEN" and "WHILE/LOOP" constructs.

    "Architecture is pretty well a content-free word in software development"

    "Architecture is the decisions that are hard to unmake" -- Attributed to Martin Fowler.  I know I've read this article before, but I couldn't find it to put a link in.  As I recall, Martin borrowed a definition of architecture from one of the GoF guys that goes something like - "Architecture is the technical decisions you consider to be the most important"

    "AJAX makes the web suck less"

    "[The Document Object Model] is an API designed by a committee to appeal to nobody" -- the speakers as a whole were not kind to the W3C and OASIS

    "If you don't know if it runs, why bother compiling it?" -- one of many verbal digs at people being afraid of dynamic languages

    "Code that's difficult to test is difficult to use" -- Pay attention to your API when you're testing. Use TDD as a tool to sand off the rough edges on your public API

    "Rails makes it easy to do the right thing!" -- I'm going to talk about this more below, but it's one of the underlying principles of RoR (and I think they're largely succeeding)

    "In five years, compiling will be considered to be just a weak form of testing"

    "The peripherally technical management crowd grabbed SOA like a chew toy" -- I actually do believe there is some actual value in SOA, but I've always suspected, and observed, that some of the popularity is due to non-coding architects pushing SOA as a chance to feel important again

    "SOA as an acronym no longer holds any value" -- Just complaining about the sloppy abuse of the term to mean anything the speaker or writer wants it to.  I know, you could easily slip "Agile" in for "SOA" in that sentence (MSF for Agile?, agile my @!*)

    "Low Truck Number" -- A statistic measuring the healthy duplication of knowledge and understanding within a project team. If your Truck Number == 1, a single person getting hit by a bus, or offered more money across the street, effectively ends your project. I've been the "what if you were hit by bus" guy in the past. It wasn't fun, and I learned to hate that phrase.

    "I think the popularity of SOA can probably be traced to an article in an on-flight magazine"

    "Writing a lot of noisy code just to make the compiler shut up" -- Again, moving to dynamic languages.  The speakers were, almost to a man, in favor of dynamic languages.  More on that below.

    "Code is the most important artifact you create" -- Amen.  This was from a talk on improving code in general.

    "Am I going to choose a tool that protects me from myself, or pick the sharpest possible tool?  Even if it means I might cut myself?"  -- Austinite Bruce Tate launching into a talk about the Metaprogramming approach used by ActiveRecord (RoR's O/R mapping tool)

    "Seaside is the coolest thing you'll never use"

    It's the Community: .Net vs. Java vs. Ruby

    In my opinion, one of the coolest things about Ruby in general and Ruby on Rails in specific is the energy and can-do spirit of the Ruby community.  If Ruby/Rails succeeds in taking away market and mind share from J2EE or .Net it will be directly attributed to the strength of its community.  I'm very impressed with the amount of energy and community-driven innovation that's going on in the Ruby world.  What's cool to me is that the innovation is coming from a community of practitioners instead of being solely reserved for the one big company working in a relative vacuum.  Check out Streamlined (new open source tool to accelerate building Rails screens), I was absolutely floored by the five minute demo.  I'm unapologetically a believer and an enthusiast for open source tools and frameworks.  We've got some good ones in .Net, but nothing like Rails is cooking up (I don't mean to discount MonoRail, I just think it's ramming a square peg through a round hole).

    .Net doesn't have anything that remotely compares.  Andres Heilsberg and co in Redmond are doing some truly innovative things, but where's the community driven innovation?  When I read Ruby blogs I see a lot of "look at this new, cool plugin I made for Rails."  In .Net blogs I see a much, much higher percentage of "look at the new thing from MS that'll be available someday."  Make me feel better and tell me I'm wrong about .Net.

    Some people in the .Net world have openly criticized Microsoft for working simultaneously on 3(?) different O/R-ish persistence frameworks based on LINQ (none of which may be any better than NHibernate).  I say, bring it on and let the best tool win!  We (.Net) don't have much in the way of diversity in terms of our tooling.  Some of the J2EE guys were complaining about the variety of choices they have to make to do an enterprise system -- WebWork, Tapestry, Spring, Struts, and who knows what else for web development.  All I've got is ASP.Net and some ports.  I understand their pain, but I think we (.Net) would be better off if there was more choices.  Look at Internet Explorer, it was essentially dead until Firefox came along to push it.

    Collectively, our little cadre of .Net folks agreed that we like our .Net tooling for TDD (NUnit + TestDriven.Net) much better than the tools we saw the Java guys using.  Just for an example, the poor Java guys don't have [ExpectedException(typeof(SomeCustomException))] yet.  Ha, ha.

    Of course it's not really fair to compare the two communities.  Ruby is largely a collection of early adopters and .Net is a mainstream language.  The community makup is obviously going to be very different.

    Maybe You Should Have the Smart Guys Writing Code

    Sitting in Neal Ford's session on improving the quality of code.  It was just a nice session going over basic principles of good coding -- naming, Composed Method, etc.  In other words, nothing revolutionary.  What was striking was that this talk about low level coding was being given by an acclaimed Application Architect.  A really smart guy was spending time talking about coding.  For that matter, almost every single talk I attended talked about coding.  In other words, coding is important.  Coding requires skill and judgment.  Coding isn't something you just throw over the wall to a bunch of monkeys with keyboards.  It's possible that the best book about coding I've ever read is Refactoring by Martin Fowler.  Martin Fowler apparently thinks that low level, hands on coding is important.  So why do we still have so many shops trying to write software by surrounding one or two competent people with an army of poor coders, then disallow the competent fellows from coding?  The non-coding architect/spec coder combination has to be one of the worst possible team models, yet it's so common.  Removing your best people from hands on coding has never seemed very intelligent to me.  I thank God every day that I jumped to an XP shop 3+ years ago when I was getting rammed into the powerpointing, non-coding architect peg.  It makes me shudder in horror to think what would have happened to me if I hadn't gotten out of there.  I bet I'd be blogging about SOA a lot more;)

    It's Firefox for Me

    I'm often slow to jump on some things just because I don't pay enough attention.  I've largely ignored Firefox because I really don't have any major hangup with IE.  After seeing the plethora of web development tools in Firefox that were used in some of the Ajax and Selenium talks, Firefox is now my browser of choice.  There you go, I have to be nearly the last developer converted.

    Selenium IDE

    I'm going to do a short post later this week on integrating the Selenium web testing engine inside of FitNesse.  I still like that approach for acceptance tests, but I think we'll supplement that with the Selenium IDE tool.  Selenium IDE is a nifty Firefox plugin that allows you to record and/or edit Selenium tests inside the running browser.  My initial thought is to get our tester to use this as the mechanism to communicate defect reproduction steps.  It might be asking too much, but it would be nice if they would also use the tool to create a test for the correct fix, but let's not get too far in front of ourselves.  One of the problems you face with defect reports is vagueness and ambiguity in the description of a defect and the expected results.  Human-readable, automated tests are my favorite mechanism to eliminate that ambiguity.

    What's Still Stopping me from using Ruby

    Inertia.  Legacy code.  "Enterprisey" stuff like support for x509 certificates.  The tooling needs to catch up.  I'm not very wild about any of the Ruby tools I've tried so far (I can't even get RadRails up yet).  I'm going to give Sapphire in Steel a try pretty soon.  I really, really don't like programming without automatic refactoring.  I'm not too keen on coding without being able to quickly go "SHIFT-F6" to rename anything.  Ruby is going to have to have a strong refactoring tool at some point to win a lot of people over.  As often as I've heard "Neck Bearded Unix Guy" gush on about the old Smalltalk Refactoring Browser it's a safe bet that it's technically feasible.  I really want to hear JetBrains announce a Ruby IDE.

    Oh yeah, there's that little "we're a .Net shop" political issue.  In all seriousness, we have some internal facing administrative tool work coming up that might have skunkworks "Ruby on Rails" trial project written all over it.

    More Later

    There will be more.  After I get a chance to digest a little bit, and let some of the Koolaid out of my system, I'm going to weigh in on the Static vs. Dynamic language debate.  I'm definitely going to collect some thoughts about Rails.  There's also a host of technical things about the way Rails works that I like much better than ASP.Net.  If nothing else, I want to talk about how Rails blows ASP.Net out of the water in terms of testability, and maybe getting some of that goodness into .Net. 

  • Some great posts

    There seems to be a bushel load of great blog posts the last couple of days.

    Jay Flowers has a Tour De Force article presenting the beginnings of a metric to measure the testability of code.  One major reason newcomers to TDD become discouraged and struggle with TDD is that they're not writing testable code.  If you're new to TDD the very best advice I can give you is to just assume from the beginning that you must change the way you code.  TDD is going to put a much higher priority on loose coupling and stronger cohesion than you might without TDD.  Jay is working towards providing guidance tools for TDD newcomers to aid in TDD adoption, especially with legacy code.

     

    Cory Foy has a nice post entitled We're only as agile as our process about dealing with bureaucracy.  I have a nearly absolute lack of patience for any kind of red tape and I feel his pain.

     

    Switching gears, Scott Hanselman had a post yesterday about using JSON as a serialization mechanism to send data between Javascript/AJAX pages and the backend.  JSON is native to Javascript and ends up being a much easier transport mechanism to deal with in Javascript that Xml.  I've been using JSON a little bit in combination with Prototype's Object.extend() method to setup classes in Javascript.  The really cool thing I haven't tried yet is that Ruby uses something called YAML as its serialization markup language that is at least partially compatible with JSON.  Anyway, I was surprised when I first started reading about JSON this spring.  Apparently it is perfectly possible to build entire systems without a lick of Xml.  I know, absolute heresy.

  • Is UML Important?

    I'm spending a lot of time today running some *slow* build scripts and FitNesse tests, so I've got time to throw this out.  In my last post I linked to an article by Robert Glass that more or less called into question the usefulness of UML. 

    Martin Fowler covers the issues around UML on his bliki here.

    I still quite happily use UML in the UmlAsSketch mode, but not nearly as much as I did 4-5 years ago.  I've always claimed that I can teach you everything you really need to know to use UML in 15 minutes (you can just park that "Aggregation vs Composition" argument right next to "Camaro vs Mustang" in the useless bin).  Don't let the length of the bullets below fool you, I do think UML is useful.

    Yes

    • It's still the de facto industry markup for describing code
    • It is useful for communicating designs
    • Most software design books use UML notations to describe design concepts.  Learning UML will help you get more out of the existing literature on UML.
    • I like to use it as a "manipulative," a tangible artifact as a thinking aid when working through a design
    • It's a useful tool in your design toolbox

     

    No

    • Not every, and maybe not even a majority, of developers find UML to be useful or understandable.  I've simply worked with too many effective developers who do not use UML to consider it necessary.  The effectiveness of UML as a means of communicating a design is essentially eliminated if most of the team doesn't understand UML.
    • UML seems to work best for people that have a visual/kinetic learning style, and not everybody has that learning style
    • There's a point of diminishing returns with creating UML diagrams upfront.  Exceeding that point, and I think it comes fast, is just plain inefficient
    • A fancy looking UML diagram can easily create a false sense of security about a design, leading a team to keep right on chugging down a bad path.  Taking a page out of Scott Ambler's Agile Modeling book, you need to Travel Light and be prepared to challenge or chuck the existing UML diagrams at any time.  I still love the old Bertrand Meyer quote - "Bubbles don't crash."
    • Executable UML:  Pipe dream.  Maybe graphical DSL's will take off and be the bee's knees (I'm dubious on that score as well).  The idea of Executable UML with reams of OCL adornment being a more efficient means of producing software makes me say - "I'm from Missouri, and you're gonna have to show me"
    • UML as a design heuristic.  I don't really find UML to be all that useful as a means of creating a design in the first place.  I tend to scoff at things like ICONIX that are a prescriptive modeling approach to design (draw these x diagrams in this order and a workable design magically pops out the back).  I'm fully prepared to believe these methods work for their originators but I'm extremely doubtful that these methods are universally applicable.

     

  • Some stuff to think about

    Robert Glass has a nice, short article on some findings on software project success:

    http://www.developerdotstar.com/mag/articles/software_success_failure.html

     

    Something he lists as a surprise finding that bothers me:

    "Post mortem reviews are rarely held, and when they are it is almost always on successful projects "

    I'm pretty sure it's more important to do lessons learned activities when things didn't go well.  Learning from mistakes seems to make the lessons more permanent.  I think one of the signs of a healthy team environment is the ability to do retrospectives freely and calmly, then follow through with changes.  I'd call this post from Steve Eichert, detailing some hard lessons learned his team faced, a sign of a healthy team.

    One of the findings Robert Glass talked about was:

    "Success comes from a culture that investigates and deals with problems "

    I'd simply add that it helps to do retrospectives often, preferrably after each iteration and release.  Software development is still an unsettled, chaotic process.  Success seems to be largely predicated upon the frequency of your feedback cycles and your ability to make changes based on that feedback.

    Anyway, enough from me.  Go check it out.