Over a million developers have joined DZone.
Platinum Partner

How to return default(Type) in runtime – a TDD example in four unit tests

· DevOps Zone

The DevOps Zone is brought to you in partnership with New Relic.  Learn more about the common barriers to DevOps adoption so that you can come up with ways to win over the skeptics and kickstart DevOps.

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…

The DevOps Zone is brought to you in partnership with New Relic. Quickly learn how to use Docker and containers in general to create packaged images for easy management, testing, and deployment of software.

Topics:

Published at DZone with permission of Dror Helper , DZone MVB .

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}