There are a million blog posts on this sort of thing but it just bit us so I thought I’d add mine to the mix.
Date calculations can be notoriously difficult depending on the language you are using. However, DO NOT succumb to the desire to "fake" it as our vendor did. Here’s what happened:
In California every school has to submit data for their special ed students/programs to receive proper funding. This is called a CASEMIS report, and reporting day is every June 30th and December 1st.
For CASEMIS if a child is under 6 they are in one category and if 6 and over in another.
In our data there is one student in question who’s date of birth is 12/3/2002. So on the reporting date of 12/1/2008 this student will be just two days shy of 6 years old.
We were getting an error in our validation process because apparently our vendor was calculating ages using 1 year = 365 days. 12/1/2008 – 12/3/2002 yields 2190 days, which at 365 days a year results in 6 years exactly.
Ugh! Sorry, but the "close enough for government work" doesn’t apply here.
I don’t know exactly what language they are using but I believe they use perl on the back end and Business Objects InfoView XI for the reporting. The actual date calculation could be in either of these two places, or somewhere entirely different.
While some languages make calculating proper dates difficult, there is almost always a correct way to do it.
For instance, in Microsoft T-SQL, asking the difference in years between 12/1/2008 and 12/3/2002 using: SELECT DateDiff(yy, ’12/3/2002′, ’12/1/2008′) incorrectly returns 6 years, since 2008 – 2002 = 6.
However, if you change the question slightly and ask if the birthdate + 6 years is less than the reporting date using: SELECT CASE WHEN DateAdd(yy, 6, ’12/3/2002′) < ’12/1/2008′ THEN ‘6 or Over’ ELSE ‘Under 6’ END this results in the correct response “Under 6”.
It’s a matter of finding the proper question and syntax for the language.
I have a pretty decent project at my work that I am using ASP.Net MVC for. It is a great framework and it’s my first real development project in a long time so I’m pretty excited.
I’m really stealing myself to use TDD, with very heavy emphasis on the first D, “Driven”. I’m not allowing myself to write a line of code without a test first. It’s a little hard because IntelliSense is pretty meaningless in tests if the actual objects haven’t even been built. When things get a little muddy I go and create a quick empty controller or something before I finish the actual test. This is just so that I can let VS 2008 and ReSharper work their magic adding namespaces and proper syntax.
Anyway, before I get into the nitty gritty I wrote this post because I was on a search of how to unit test my custom HtmlHelpers. I found some decent posts and looked at the source for MvcContrib, but I didn’t need anything fancy. I’m just creating a file input tag. I don’t need to mock the Context or anything. I didn’t find a easy post anywhere on how to do this. It turns out if you don’t need anything special it’s quite easy indeed. If you’re looking for this then read on.
Anyway, I have a form where the user will upload a couple of files. Using Scott Hanselman’s great blog post on unit testing uploading files using MVC I have a controller that now requires two non-empty files before it returns a success view.
I’ll flesh that out a little more with some actual validation of the upload contents but for now I’m refactoring my initial form.
From Scott’s post what I began with is the following:
This doesn’t make any use of HtmlHelpers so I wanted to refactor this. There is no FileInput HtmlHelper but you could easily use the Textbox extension as in the following:
<%= Html.TextBox("tableA", null, new { enctype = "multipart/form-data" }) %>
And this would product the following correct HTML:
There are two things about this that bug me however. First and foremost, did I save any effort? The HtmlHelper code is actually longer then the straight HTML itself! In my opinion HtmlHelpers should help in some way, not just be used because they are there. So, if it doesn’t save me any extra work or protect me from something such as malformed urls or localization formatting, then there’s no point. Second is that blank value attribute. Why do I need that?
So, being the developer that I am, I thought I’d create my own HtmlHelper for a File Input textbox. Using TDD this requires that I write my test first:
namespace Tests.CECWA.Web.Helpers{
[TestFixture]
public class FileInputExtensionsTests
{
[Test]
public void CanGetCorrectOutput()
{
string html = FileInputExtensions.FileInput(null, "testName");
const string expected = "";
Assert.That(html, Is.EqualTo(expected));
}
}
}
I use NUnit but it’s pretty similar in any testing framework. FileInputExtensions is my extension class containing my custom HtmlHelper FileInput. The null parameter is the HtmlHelper class that is actually extended. Since I’m not making use of the Context or anything else I can simply pass a null in. If I were doing something fancy such as needing the base path of the app then I’d have to mock this out like the other more extensive posts do.
This test simply calls my extension method and stores the result in the html variable. I store what I expect in my expected variable. Then I assert that they are equal. Quite easy actually.
When I build my project it of course doesn’t compile since there is no FileInputExtensions class. So I do the bare minimum to compile:
namespace CECWA.Web.Helpers
{
public static class FileInputExtensions
{
public static string FileInput(this HtmlHelper helper, string name)
{
throw new NotImplementedException();
}
}
}
Everything now compiles but my test fails. So, lets complete the method:
OK, if you compare the pure HTML version and this one you don’t see much difference in the “effort”. However, this is more protected against improper paths in my form action url, typos in my various field ID’s, and just general lousy HTML coding in general.
Multiply this over several dozen pages and you start to feel a real tight management on your html output and maintainability. For instance, if I want to change the way my FileInput extension renders I simply update my test, update my class to pass and now every place a FileInput helper is used has been updated through out the site. Nice!