April 29, 2009

Unit Tests, Extension Methods, and Lambda Expressions, Oh My!

Posted in Chefbook tagged , , , , , , at 10:29 am by davy803

After taking a little detour into Python, I’m back to working on Chefbook.

First of all, I must say I’m very happy with my experience with test driven development.  As I mentioned in my first post about TDD, I’m not following the exactly process of writing and passing one test at a time.  Instead I write out all the tests I can think of for an entire class based on the functional specification.  I also write out method stubs beforehand for two reasons.  First, I like having a compiling codebase and the red underline squigglies for compile errors bothers me.  The second reason is so I get IntelliSense (Visual Studio’s auto-complete) which makes typing method names easier and less error prone.  Also since it resolves to known methods I can rename them easier later using Visual Studio’s rename feature.

The first thing that occurred to me when I wrote tests first was that it’s a lot easier to write tests that are easy to code, than it is to write code that’s easy to test.  Some of my previous attempts with writing unit tests were a bit rough because the it was hard to get code under test in isolation.  The second thing is that if you write tests first, you don’t have any preconceived notions of how the code works, all you know and need to know is what the method is supposed to do.  A lot of times when I was writing unit tests afterwards, I ended up just rewriting the code in the test, because I already saw the code and had a preconceived notion on how it was going to work.  When writing unit tests, how it works is not important, it’s what it does that matters.  Writing tests before writing code lets you break the temptation to write tests that pass because you know how the code is written.

What I also discovered, was that even though I wrote “all” the tests before starting on any code, I quickly discovered that there were more conditions that needed to be tested than I originally thought.  What ended up happening is that I would get all the tests on a method to pass and feel pretty good about it.  Then as I’m trying to get a different test to pass, I’d find out in the process of debugging that the first method wasn’t designed as thoroughly as it needed to be (because all the designed behaviors are tested).  Let’s look at an example to explain what I mean.

The Category class has an AddRecipe method that does exactly what it says, it adds a given recipe to that category.  The problem was that there was nothing to prevent the same recipe from being added to a category more than once.  That wasn’t part of the design because it didn’t occur to me that that scenario could come up.  Well, now when you delete a category, it automatically does all the cleanup work removes itself from all of its recipe’s list of categories.  As it was looping through the list of recipes, it tried to remove itself twice from the same recipe because the same recipe was in the list twice.  Here it threw an exception because, following the fail fast strategy, I throw an ArgumentException if you try to remove a category from a recipe that doesn’t have that category listed.  This lead to adding a unit test (thus changing the design, because the tests are the design in TDD) to ensure that if you try to add a recipe more than once, there will still only be one instance of the recipe in the category.

Another thing from fail fast is that I end up checking all arguments for null if it doesn’t make sense for it to be null.  There are instance where it’s allowed, for instance a category can have no parent if it’s the root category.  What ended up happening was that I ended up littering methods with ugly null checks and argument validation code like the following:

public void AddRecipe(Recipe recipeToAdd)
{
    if (recipeToAdd == null)
    {
        throw new ArgumentNullException("recipeToAdd");
    }
    if (!recipes.Contains(recipeToAdd))
    {
        recipes.Add(recipeToAdd);
    }
    if (!recipeToAdd.categories.Contains(this))
    {
        recipeToAdd.categories.Add(this);
    }
}

Luckily, C# 3.0 added Extension Methods that allows us to cleanup this code.  I’ll explain how it works shortly, but here is what this code looks like using the extension methods I added.

public void AddRecipe(Recipe recipeToAdd)
{
    recipeToAdd.ThrowIfNull("recipeToAdd");
    recipes.AddIfNew(recipeToAdd);
    recipeToAdd.categories.AddIfNew(this);
}

Looks much nicer, but how does it work?  Did I add a ThrowIfNull method to the Recipe class?  Isn’t that a big hassle to add that method everywhere it’s needed?  No, it’s not because I didn’t add it to Recipe, I actually added ThrowIfNull to the object class.  How did I do that you ask?  Well ok, I made a little fib.  I didn’t really add it to the object class.  But I can use the method as if I did.  Here’s what the ThrowIfNull method looks like:


namespace Chefbook.HelperMethods
{
    public static class ParameterValidation
    {
        public static void ThrowIfNull(this object valueToCheck, string parameterName)
        {
            if (valueToCheck == null)
            {
                throw new ArgumentNullException(parameterName);
            }
        }
        //More methods here
    }
}

As you can see, the method is in a separate class altogether. It is a static class and the method is a static method, meaning that it’s not a instance method.  But we just called the method on an instance variable.  Technically we didn’t, that’s just the magic of extension methods.  Notice that the this keyword is in front of the first parameter of the method.  This indicates that it’s an extension method.  Extension methods are syntax shortcuts, nothing more.  When I say:

someObject.ThrowIfNull("someObject");

That’s actually just a shortcut for saying:

ParameterValidation.ThrowIfNull(someObject, "someObject");

While it’s true that it may not be much shorter, the way the syntax flows makes it easier to understand and more natural.

There other extension method I have is AddIfNew.  Let’s take a quick look at that:

public static void AddIfNew<T>(this ICollection<T> collection, T itemToAdd)
{
    if (!collection.Contains(itemToAdd))
        collection.Add(itemToAdd);
}

If you’re unfamiliar with generics, this might be a little confusing to understand at first.  Check out this article for a quick intro to generics in C# if you need to.  Basically what generics give you is the ability specify the type of an object when you create an object and to constrain the type of parameters or return values.  In the example above, this is an ICollection of type T.  What T is isn’t important here, as long as the parameter itemToAdd is also of that same type T.  You’ll notice when I called the extension method I didn’t need to specify the type when I used it:

recipes.AddIfNew(recipeToAdd);

Instead of:

recipes.AddIfNew<Recipe>(recipeToAdd);

This is because I’m calling the method on recipes which was already declared as List<Recipe> so it knows that T is based on that.  (List implements IList which implements ICollection.) 

There’s one more extension method I’d like to show.  I added the method because the fact that the Parent of a Category is allowed to be null is problematic, in that I need to check if Parent is null before I can perform any kind of action on it.  It’d be nice if I could write a one-liner to do that like we did above.  But how do we do that if we don’t know what it is we need to do?  Delegates to the rescue!  Delegates are a complex topic and explaining them fully is beyond the scope of this post.  If you want to learn more about delegates, I recommend this article.  Suffice it to say that delegates are a way to pass methods as variables. 

There’s two built-in classes that encapsulate delegates so they’re somewhat easier to use (they can get quite clunky using them manually).  The first one which I used is Action, which takes 0 to 4 parameters and returns no value.  The second is Func which does the same thing except it returns a single value.  Let’s take a look at the method here:

public static void PerformIfNotNull(this object valueToCheck, Action actionToPerform)
{
    if (valueToCheck != null)
        actionToPerform();
}

It takes a parameter of type Action and then checks if the object is null and performs the action if it’s not null.  If we wanted the Action to take one parameter, then it’d look like this:


public static void PerformIfNotNull<T>(this object valueToCheck, 
    Action<T> actionToPerform, T param)
{
    if (valueToCheck != null)
        actionToPerform(param);
}

Notice we need to pass in the argument for actionToPerform as a separate parameter (param).  Notice also we use T to specify the type of the paramter.  By the way, “T” isn’t a special name or anything, it’s just a naming convention for generics  What’s important is that it’s declared as a generic type in the method signature by putting in inside brackets.  If we wanted the method to return a value we could use Func instead of Action and it’d look like this:

public static TResult PerformIfNotNull<T, TResult>(this object valueToCheck,
    Func<T, TResult> actionToPerform, T param)
{
    return actionToPerform(param);
}

Notice we declared an additional generic type, TResult.  We need to specify the return type for a Func, and we do that by declaring it both in the method signature and in the return type.  Now this method doesn’t really do anything useful, since we’re just calling a function to call another function, but just explaining the syntax for the sake of example because that was something I had trouble with for a while.

Now that we see how the method is declared, let’s see how it would be used.  We are assuming the first example of PerformIfNotNull (the one that takes an Action that takes 0 arguments and returns void).

public Category Parent
{
    get { return parent; }
    set
    {
        parent.PerformIfNotNull(delegate()
                    { this.parent.subcategories.Remove(this); });
        this.parent = value;
        value.PerformIfNotNull(delegate() { value.AddSubcategory(this); });
    }
}

Here we introduce a concept called anonymous methods.  I won’t discuss them too much in here but this is a great article for learning about anonymous methods in C#.  You’ll recall that our extension method takes an argument of type Action, which is a method that takes 0 arguments and returns nothing.  Here we are using the delegate keyword to create a new nameless method.  It takes no arguments because there is nothing inside the delegate() parentheses.  If we wanted a delegate that takes an int as a parameter, we would use delegate(int i), and then we could use i within the anonymous method.  One thing to note that is great about anonymous methods is that they are declared inside the scope of the parent method, so it has access to all the instance variables: parent, and this, as well as the local variable value which is automatically created for us by the set method.  If we were to use a normal method (which we could) we would need to pass in the variables we needed to use as parameters.  Actually if you read the article I linked above, you’ll see that there’s a lot of magic going on under the hood to make it possible to use local and class variables in anonymous methods, but for the most part we can just pretend that the methods exist in a more local scope which always inherits variables in a higher scope.

So what does this method do?  Well, when we set a new parent, we want to remove this category from the old parent so that we aren’t listed as a subcategory anymore.  But remember since we allow Parent to be null if it’s the root category, we need to check if parent is null before we try to remove ourself from it.  Then we want to add ourself to the new parent but again only if it’s not null, so we use our PerformIfNotNull method again.

There’s actually another shortcut for anonymous methods which I’m actually going to use.  Let’s just see what it looks like before I explain it:

set
{
    parent.PerformIfNotNull(() => this.parent.subcategories.Remove(this));
    this.parent = value;
    value.PerformIfNotNull(() => value.AddSubcategory(this));
}

We’ve replaced the delegate keyword with just an empty set of parentheses, and we use a little arrow thing.  Also notice we got rid of the inner curly braces and semicolon from the previous example.  What this means is that we’re defining a method that takes 0 parameters.  This is really just a minimal use of lambda expressions to shorten the syntax slightly, but lambda expressions are more powerful than that.  This article describes lambda expressions pretty well and gives a little more insight into what you can do with them.

Before wrapping up, I mentioned earlier that we wanted to do some parameter validation and throw exceptions if the parameters passed in weren’t valid.  Well it sure would be nice if we could unit test that.  Well we can.  Let’s take a look at two of our tests.

 

[Test]
public void ChangeCategoryTest2()
{
    var cat1 = new Category(root);
    var cat2 = new Category(root);
    Assert.Throws<ArgumentException>(() => testRecipe.ChangeCategory(cat2, cat1));
}

[Test]
public void ChangeCategoryNullTest1()
{
    var cat2 = new Category(root);
    Assert.Throws<ArgumentNullException>(() => testRecipe.ChangeCategory(cat2, null));
}

 

The first one should throw an ArgumentException because ChangeCategory is supposed to move the recipe from the first category to the second and testRecipe isn’t in cat2.  For the 2nd test we throw an ArgumentNullException because one of the categories passed in was null.  I upgraded to NUnit 2.5 which is in Beta3 right now.  The reason is because of the new cleaner syntax for asserting that an exception is thrown.  Previously you’d have to declare an attribute on the test that it expects an exception, but that just means that that exception is thrown anywhere in the test.  To capture an exception being thrown specifically from one method call, we need to either use the new Assert.Throws syntax in NUnit 2.5 or we need to put an ugly try/catch block around the code in question.  This post describes how the different ways of capturing an exception in NUnit can be done.  (Just a note, the last example with getting the parameters of an exception didn’t work for me, so maybe it was changed, since it’s still in Beta right now.)  You’ll notice I pased in the method as a lambda expression.  You’ll see lambdas beng used fairly often in the codebase.

 If you want to look at the code from this post you can either look at it here or check out revision 14 from the svn repository.