Wednesday, December 07, 2005 - Posts

DuckUnit

Some weeks ago I downloaded the new beta of Test Driven .NET. As you might know the beta is available through Folder Share, which basically is a peer to peer network. Trying to support Jamie’s excellent tool I kept the share open to help distribute Test Driven .NET. A cool side-effect from this is that I automatically get all the latest files downloaded to my computer. I’ve got my shared folder in a sub folder beneath My Documents, and my information client of choice; Jet Brains’ excellent Omea Pro keeps track of changes to files in My Documents. Earlier today I noticed that a mysterious, new folder named DuckUnit had appeared. When I opened the folder to take a closer look at what it was I discovered the creator of Test Driven .NET, Jamie Cansdale was up to something again. DuckUnit is a testing framework that let’s you specify units test by applying a custom XML code comment named test to your methods. For example:

    /// <test x="1" y="2" z="3">6</test> 
public int Sum(int x, int y, int z)
{
return x + y + z;
}

The attributes correspond to the arguments of the method, and the inner text of the element to the expected result. The framework also lets you define your test data in separate XML documents, using the standard include directive:

    
    /// <include file="PrimeTests.xml" path="tests/test/" />
    static bool IsPrime(int num)
    {
     int max = (int)Math.Sqrt(num) + 1;
     for (int count = 2; count < max; count++)
     {
      if (num % count == 0) return false;
     }
     return true;
    }

The need to have some arbitrary test data to use within your unit tests is common. Usually I’ve restored to having DataSets with test data or serialized mock objects stored as XML within my test projects. I really like the idea of being able to inject test data into my unit tests in a declarative fashion. Especially when you can use the include statement to separate the test data from the actual test. I’d really like to see some examples of how to use more complex types as arguments for the test methods, but a primitives only solution is a good start. Maybe parameterless unit test soon will be a relic of days gone by?

Dynamic Methods and Humane Interfaces

One of the key differences between C-style languages such as C# or Java and Ruby is how libraries are designed. The Ruby crowd has coined the term “Humane Interface” describing their style of defining class interfaces. A good example is Ruby’s List type which exposes a whooping 78 instance methods, while .NET’s ArrayList class has less than twenty if you leave out the overloads. The generic List<> in .NET 2.0 has some more, but still the methods are all low-level. A good example of syntactic sugar in Ruby’s List is the flatten method which flattens a multi-dimensional array.

[1,2,[3,4,[5,6],7],8].flatten => [1, 2, 3, 4, 5, 6, 7, 8]

When I teach developers about refactoring, I often use an example I’ve borrowed from Joshua Kerievsky’s Refactoring to Patterns book to show how code can be more readable or more humane if you like; November(20, 2004) where November is a public static method accepting the day of month and the year as its arguments. The November method communicates its behavior better compared to new DateTime(2004, 11, 20) which requires you to have knowledge of the System.DateTime constructor.

Examples like the one above might seem a bit over the top, but successful Ruby frameworks such as Ruby on Rails have similar methods that have been essential to the libraries success. For instance; Ruby on Rails has a pluralize method which gets the plural form of most English nouns. Why would you need such a method? The answer lies in Ruby on Rails convention over configuration philosophy, where instances of a User class are expected to be persisted in a Users table in the database. The pluralize method makes this convention easy to apply.

John Lam has been doing some really interesting experiments with programming Ruby with the CLR, and his latest project is a great example of how Ruby’s humane interface philosophy makes Reflection.Emit, which is one of the least approachable namespaces within the .NET framework, much easier to use.

    create_ruby_method('say_hello') do
ldstr 'Hello, World'
call 'static System.Console.WriteLine(System.String)'
ldc_i4_4
ret
end

Above is an example of how to use his RbDynamicMethod library to create a CLR DynamicMethod from Ruby. Although MSIL still is cryptic to most, being able to write “MSIL code” within the source code is much easier than using OpCodes to emit MSIL code. Below is the same example using the .NET 2.0 Lightweight Code Generation (LCG).

    public class DynamicMethodExample
{
public static void Main(string[] args)
{
DynamicMethod method = new DynamicMethod("SayHello",
typeof(void), new Type[] {}, typeof(DynamicMethodExample), false);
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Ldstr, "Hello, World!");
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
new Type[] { typeof(string) }));
gen.Emit(OpCodes.Ret);
}
}

The lightweight in LCG has its place. In .NET 1.x you could emit the Hello World part of the above example in three lines of code, but you would typically need approximately 10 more lines of code to setup the classes needed to do this. The LCG is a huge improvement, but I still find John’s MSIL code more appealing than using reflection to get hold of MethodInfo’s and similar.

Another example of how class interfaces can be more humane is .NET’s EventLog class which throws an ArgumentException with information on how to resolve the error when the class is used without being properly configured. Such a message gives developers instant clues on what might be wrong, and can save them hours of mucking about with the debugger.

The syntactic sugar added to C# 3.0 and Visual Basic 9 in particular make the languages more expressive, and the LINQ framework provides a great abstractions allowing developers to do complex operation in just one or two lines of code. These new additions to the .NET development environment make the general developing experience more humane. Humane interfaces are a trend that reaches way beyond the small Ruby community, and you should always look for options to make your class interface more humane. Even if your core classes might require more maintenance over time, the client code will be easier to maintain since the code base will be much smaller, more expressive and readable.