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).
[From Wikipedia]
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.
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.
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; } }
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.
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…
Labels: C#, NUnit, TDD, Unit tests