What is TDD? How to get started with Test Driven Development

Posted written by Paul Seal on June 15, 2017 Tips

What is TDD?

TDD stands for Test Driven Development . TDD is a method of writing code which is proven to be correct by writing tests. The approach is, before you write any code, you should write your tests which set out the rules, guidelines and expectations of the code you are going to write. These tests will obviously fail at the beginning as you haven't written any code yet. But as you write the code, more and more of the tests will pass. This will give you the confidence that your code is correct. If you find more scenarios where you think it would make it fail, write a test for it and see. If you find a bug in your code, write a test for it.

A great benefit of TDD is that with your tests already written and passing, when you come to refactor the code, you will get instant feedback to say whether it still works or not.

How to get started?

I find that I learn things better by trying it myself so in this post I have an example task to go through which is an ideal one for TDD.

About the task

About 5 years ago, as part of an interview process I was asked to write some code which would validate UK National Insurance Numbers.
In this test there was certain criteria which had to be met and proven, in order to pass.

Rules and criteria:

1. Must be 9 characters in length
2. First 2 characters must be alpha
3. Next 6 characters must be numeric
4. Final character can be A, B, C or D.
5. First character must not be D, F, I, Q, U or V.
6. Second character must not be D, F, I, O, Q, U or V.
7. The first 2 characters must not be combinations of GB, NK, TN or ZZ (the term combination covers GB and BG etc).

Important Note

The criteria above is what we are going to base our tests on. So you need to make sure you know up front what the requirements are in order for you to write the appropriate tests.

We will attempt to solve this using TDD

Let's start by creating a console application in Microsoft Visual Studio 2017 Community Edition, you can download Visual Studio from here https://www.visualstudio.com/downloads/

Once you have it installed, open Visual Studio and click on File > New Project

Choose C# > Class Library(.NET Framework)

Enter a name for the project, I called mine NINumberValidator

Choose a folder for it to be saved to, you might want to tick the box to create a directory for the solution. Then click on OK.

You should end up with a file open called Class1.cs which looks like this:

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

Now we need to add a test project to the solution.

In the Solution Explorer window, right click on the solution and click on Add > New Project

Under Visual C#, choose Test, then choose Unit Test Project (.NET Framework)

Enter a name for it, I'm calling mine NINumberValidator.Test

It should create a file for you called UnitTest1.cs which should look like this:

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

We are all set now to get started.

So we need to create rename our class in the Main project NINumberValidator from Class1 to something more meaningful.

I'm going to rename mine to NIValidator.cs

And in the file I am going to change the name of the class to NIValidator too.

Now lets add a method called IsValid and get it to return a bool.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

Before we write any proper code, lets write some tests.

Go to the Test Project, rename file UnitTest1.cs to NIValidatorTests.cs
The in the file itself, change the class name to NIValidatorTests

We need to add a reference to the Class Library project NIValidator.
We do this by right clicking on the NIValidator.Test project and clicking on Add > Reference
In the left menu, choose Projects > Solution and then tick the project NINumberValidator, and click on OK
Now we can use this library in our test project.

The test we will write are dictated to by the rules stated in the specification.
To start with we are going to enter the first case regarding the length of the string entered. We are going to test a value where we know the code should return a value of false.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

Save the file and click on Build > Build Solution in the top menu.

You should see that it built correctly, but it won't have run the test.
You need to open the test explorer window by going to Test > Windows > Test Explorer
Then in the top left click on Run All.

You will find that the test failed. This is because we set it to return an error of the type NotImplementedException.
We do this to make sure we don't forget to implement something.

So, now we have our first test, and it is failing

We need to write the code in the IsValid method to get it to pass.
So essentially in order for the test to pass, we need to return false when the length of the string passed in is not equal to 9 characters in length.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

If we build the solution and run the test we should find that the test passes. Woohoo.
Well done, this is test driven development in its simplest form.

But we have other criteria to meet.

Lets continue to check the length. Lets add a test where the string is less than 9 characters, and one where it is empty.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

All of these tests should now pass. Don't forget to build and run all tests.
You can set it to run all tests after build by clicking the icon with an arrow and a play icon on it, above where it says Run All.

What happens if we pass a null value in? Well lets write a test for that.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

After a build and run all, this test should fail, because the method .Length property is not available on a null value. So we need to edit our code to make sure it is not null first.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

If you now build and run all the tests again, they should all pass.
Lets add a test for a string which is 9 characters long and so we expect it to pass.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

Notice the assert is now set to Assert.IsTrue. If you do a build, it should run the tests and they should all pass.

This is all well and good, but it only satisfies the first rule about the length of the input.

We need lots of tests

To save time here and so this article doesn't get too long. I've gone ahead and written all of the tests to meet the rest of the criteria.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

Lets run it and see where it fails.

When they fail, you can see what they failed on very easily because of the naming convention we used.

Now let's write the rest of the code to make all of the tests pass.

System.InvalidOperationException: No macro found by alias Gist
   at Umbraco.Web.Macros.MacroRenderer.Render(String macroAlias, IPublishedContent content, IDictionary`2 macroParams) in D:\a\1\s\src\Umbraco.Web\Macros\MacroRenderer.cs:line 209
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(IPublishedContent content, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 131
   at Umbraco.Web.UmbracoComponentRenderer.RenderMacro(Int32 contentId, String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoComponentRenderer.cs:line 102
   at Umbraco.Web.UmbracoHelper.RenderMacro(String alias, IDictionary`2 parameters) in D:\a\1\s\src\Umbraco.Web\UmbracoHelper.cs:line 178
   at ASP._Page_Views_Partials_grid_editors_Macro_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Macro.cshtml:line 15
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
   at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Partials_grid_editors_Base_cshtml.Execute() in E:\HostingSpaces\CodeSharePaul\codeshare.co.uk_ffXSTxNs\wwwroot\Views\Partials\grid\editors\Base.cshtml:line 20

They should all pass now.
What is great now, is that you can refactor the above code be confident that if you break it, the tests will highlight where the errors are.

What next?

Now you've had a basic introduction to Test Driven Development, you can go and try it on your own projects.

There is a lot more to TDD, but this was just a simple introduction into using it to solve a real world problem.

I've added my solution to GitHub if you want to download it and play with it. https://github.com/prjseal/NINumberValidator