Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

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. 

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.