RSS
Facebook
Twitter

Sunday, July 17, 2011

I’ve found this question while going over my old StackOverflow answers:

I'm using reflection to loop through a Type's properties and set certain types to their default. Now, I could do a switch on the type and set the default(Type) explicitly, but I'd rather do it in one line. Is there a programmatic equivalent of default?

I encourage you to read till the end before checking my answer – because I want to show you how this task can be solved using TDD (Test Driven Design).

File:Test-driven development.PNG

[From Wikipedia]

Test #1 – handle null input

Let’s write the first test – when null is passed return null:

[Test]
public void GetDefault_PassNull_ReturnNull()
{
    var result = DefaultCreator.GetDefault(null);

    Assert.That(result, Is.Null);
}

Now all we need is to make the test pass and so implementing this requirement is as simple as can be:

public class DefaultCreator
{
    public static object GetDefault(Type type);
    {
        return null;
    }
}

Although this seems like cheating this is the way to create the design piece but piece, instead of creating it all upfront I hope that things would get clearer in the process just keep in mind that the worse case scenario is that we have a test that checks what happens if null is passed.

Test #2 – reference types

Next test - if T is an object default(T) will return null:

[Test]
public void GetDefault_PassObject_ReturnNull()
{
    var result = DefaultCreator.GetDefault(typeof(object));

    Assert.That(result, Is.Null);
}

Running the test shows a cool feature of test driven design – the test passes! and so right now we have a class that satisfies two out of three of our requirements.

Test #3 – primitives

All we need to implement now is how to behave when a value type is passed – and so we write another test:

[Test]
public void GetDefault_PassInteger_Return0() 
{
    var result = DefaultCreator.GetDefault(typeof(int));

    Assert.That(result, Is.EqualTo(0));
}

And write the simplest solution that makes it pass:

public class DefaultCreator
{
    public static object GetDefault(Type type)
    {
        if (type == typeof(int)) 
        {
            return 0;
        }

        return null;
    }
}

So far so good but we’re not done yet – after writing a few more tests for double, float and long refactoring brought this solution:

public class DefaultCreator
{
    public static object GetDefault(Type type)
    {
        if (type.IsPrimitive) 
        {
            return 0;
        }

        return null;
    }
}

Test #4 – Structs

Still with me good – what about a complex value type :

[Test]
public void GetDefault_PassStruct_ReturnEmptyStruct() 
{
    var result = DefaultCreator.GetDefault(typeof(MyStruct));

    Assert.That(result, Is.TypeOf<MyStruct>());
}

Now that we have a failing test – we can add functionality to fix it:

public class DefaultCreator
{
    public static object GetDefault(Type type)
    {
        if (type.IsValueType) 
        {
            return Activator.CreateInstance(type);
        }

        return null;
    }
}

Run all of the tests and that’s it – we have a class that mimics default(T) at run-time one step at a time.

The end

Of course I could have created this class without unit tests but I wanted to show a simple (but not too simple) example that shows how to use unit tests as a design tool.

 

Happy coding…

1 comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...