15 Jun 2017
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.
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 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.
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).
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.
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
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
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
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.
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.
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.
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.
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.
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