Unit-Testing in Unity

CJ and I are collaborating to build an app that teaches you how to solve single-variable algebraic equations like this:

2x – 4 = 16

Our target audiences are kids and teachers, so it was obvious to us that this would be a mobile app.  For me, the choice of development platform was also a no-brainer – Unity:

  • Katherine and I had tinkered with Unity a while ago, so I was already familiar with it
  • It can generate binaries for every platform we’re considering, and then some (XBox or PS4 anyone?)
  • One of the primary programming languages supported was C#
  • Unity integrates with Visual Studio (you can also use MonoDevelop, but if you know and love VS, why?)
  • Unity has a flourishing user community
  • I could get started for free

One of the very first things I figure out with any new development language / platform / IDE is how to build unit-tests with it.  As it turns out, Unity has a built-in test-runner based on NUnit (yet another point of familiarity for me).  The runner is available under the Window menu, but normally I leave it docked on the right side of the IDE.

10

Now the next step was figure out WHERE my tests should actually live.  After a little digging I found an article on the Unity Test Runner.  The test runner has two modes – Play and Edit.  I started with Edit, and (as the article shows), there was a button for “Created EditMode Test”.  I clicked it, and it created a folder called Assets/UnitTests/Editor.  I tried renaming and moving the folders in that string, and kept on eye on the test runner – would it find my test if I put it in a folder called this?.  As it turns out, the “Editor” folder has special meaning for Unity.  I settled on a folder structure of Assets/Editor/UnitTests (inverting what Unity created by default), so I could add other Editor scripts later if I needed.

20

Now that I had the basic structure, it was time to get down to business, and start writing the logic for the game.  Fast-forward several weeks and 450+ unit tests later, and I have a few observations about unit testing in Unity.

The integration between the Unity IDE and Visual Studio is fairly seamless.  I can add a new test in the latter, switch back to the former (where it kicks off a compilation in the background automatically), and see it appear a second or two later.  In Studio, there is a preset button for attaching to Unity, allowing me to debug through my test and business logic easily.  The one minor quirk is how Unity reports compilation errors – subtly, at the very bottom of the Unity UI:

30

This stung me a couple of times – I would make some typographical error, miss this clue that my new code wasn’t actually compiling, and re-ran my unit tests expecting a change, only to find that the same test was failing because my new code wasn’t actually being used yet.  To avoid this, I now do an explicit compilation in Studio, and let Studio throw up the errors and warnings I’m used to seeing.

As a whole, the test runner does its job reliably.  One thing I’d change, though, is how it reports the current state of the tests.  If you’ve already run your test suite once, and want to run it again, Unity doesn’t clear all of the green (and red) flags for the already-run tests.  Unless something switches from red to green or vice versa, you really don’t have any indication which test is being run at the moment, how far it is through the suite, etc.  There IS a progress bar that appears while the tests are being executed:

40

And once that disappears you know it’s done, but I’d prefer the test statuses to be cleared before each run so I can watch it work through the suite again, fresh.

I’ve also noticed that the tests run much faster if you keep the focus on Unity the whole time.  More than once I would kick off a series of tests, and switch to some other window while they ran, and found my tests were still running long beyond when they should have (I’ve seen suites take 2-7 times longer to complete this way).  Again, a relatively easy issue to avoid – don’t switch away from Unity while the tests are running – but an odd one.

Overall, I’m very happy with my choice of Unity.

Advertisement

Verifying the new world order

On the iSelf project, I needed to validate that lists of things were being returned in the correct order.  I knew I would have to do this over and over, and the thought of writing tests like this made me cringe:

Assert.Equals(1, ListOfSomeClass[0].SomeProperty, "SomeProperty 0 didn't match");
Assert.Equals(4, ListOfSomeClass[1].SomeProperty, "SomeProperty 1 didn't match");
Assert.Equals(9, ListOfSomeClass[2].SomeProperty, "SomeProperty 2 didn't match"); 

I decided to try my luck creating a generic function that I could pass the test values, the expected values, and a function to evaluate the two lists.  After a few iterations, here is what I came up with:

public void VerifyPropertyValuesInThisOrder<TTestValues, TExpectedValues>(List<TTestValues> ValuesToTest, 
                                      Func<TTestValues, TExpectedValues, Boolean> EvaluationFunction, 
                                      params TExpectedValues[] ExpectedValues)
{
    if (ValuesToTest == null && ExpectedValues == null) { return; }
    if (ValuesToTest == null) { Assert.Fail("ValuesToTest was null while ExpectedValues was not."); }

    Assert.AreEqual(ExpectedValues.Count(), ValuesToTest.Count, "ValuesToTest and ExpectedValues didn't have the same number");

    for (int i = 0; i < ValuesToTest.Count; i++)
    {
        Assert.IsTrue(EvaluationFunction(ValuesToTest[i], ExpectedValues[i]), 
                        String.Format("Answer[{0}] was wrong.  Expected: '{1}'", 
                        i, 
                        ExpectedValues[i]));
    }
}

This allows me to check entire lists of things – either lists of simple values, or properties of more complex objects – with a single call.

this.VerifyPropertyValuesInThisOrder<int, int>(TestValues,
                                               (a, b) => (a == b),
                                               1, 3, 5, 2);

 

this.VerifyPropertyValuesInThisOrder<TestClass, Boolean>(TestValues,
                                                         (a, b) => (a.BooleanMember == b),
                                                         true, false, false, true);

For most of my tests, the order that the values appeared in the list were important.  However, if you need to verify that all of the expected values appear in the list, without regard to their order, simply sort both lists before you pass them in.

this.VerifyPropertyValuesInThisOrder<int, int>(TestValues.OrderBy(i=>i).ToList(),
                                               (a, b) => (a == b),
                                               1, 2, 3, 5);   

Here is a complete working example program showing VerifyPropertyValuesInThisOrder.  This sample requires NUnit 3.0.1, easily available through NuGet.

Will you just wait a minute?! NUnit and Async/Await

I was being a good-doobie.  Honest.

I had written a prototype – just something to prove that a particular approach could work.  It did, and so now it was time for me to actually bring that code up to production quality.  Part of that meant modifying how I was invoking the third-party web services – they  needed to be done asynchronously.

So I went through and wrote my unit tests to also run asynchronously:

        [Test]
        public async void Divide_4DividedBy2_Equals2()
        {
            AsyncUnitTest.Math MathLibrary = new AsyncUnitTest.Math();

            float Quotient = await MathLibrary.Divide(4, 2);

            Assert.AreEqual(2, (int)Quotient);
        }

I ran it through NUnit on my machine, and everything was peachy-keen.  I ended up writing nearly 50 unit tests* like that, converting over all of my calls.  I committed the code, and let TeamCity take over.

And watched every one of those new tests break.

When I looked at the TeamCity log, the errors seemed to hint that the test runner was simply not waiting for the thing under test to complete before trying to run the asserts.  I started searching for things like "nunit async", and pretty quickly across this two-part series by Stephen Cleary:

In this series, Cleary says that the underlying problem of running async tests is that they don’t have a proper context:

We’ve encountered a situation very similar to async in Console programs: there is no async context provided for unit tests, so they’re just using the thread pool context. This means that when we await our method under test, then our async test method returns to its caller (the unit test framework), and the remainder of the async test method – including the Assert – is scheduled to run on the thread pool. When the unit test framework sees the test method return (without an exception), then it marks the method as “Passed”. Eventually, the Assert will fail on the thread pool.

His solution is to simply give the test an async context, and he provides a very handy wrapper to do just that.  I first had to install his Nito.AsyncEx NuGet package, and then wrap my test in AsyncContext.Run:

        [Test]
        public void Divide_4DividedBy2_Equals2_Asynchrofied()
        {
            AsyncContext.Run(async () =>
            {
                AsyncUnitTest.Math MathLibrary = new AsyncUnitTest.Math();

                float Quotient = await MathLibrary.Divide(4, 2);

                Assert.AreEqual(2, (int)Quotient);
            });
        }

Notice that I’ve removed the "async" keyword from the test itself; AsyncContext.Run does all the work here.  After updating and committing my first test using AsyncContext.Run – a test test, if you will – it ran successfully on TeamCity.  I updated the other 48, and finally got a green build.

***

My build was stable again, but Cleary’s explanation didn’t answer the question of why this worked on my machine in the first place – without using his very awesome library – so, I kept digging.

I first looked up exactly what TeamCity was using to run the tests – it was NUnit, the same as what was on my machine, with a minor different in the version.  My local copy was 2.6.2, while the version on the build server was 2.6.1.  Could there be a difference in how 2.6.1 was handling async?

Why yes.  Yes there was.  In the NUnit 2.6.2 release notes I found this:

When running under .NET 4.5, async test methods are now supported. For test cases returning a value, the method must return Task<T>, where T is the type of the returned value. For single tests and test cases not returning a value, the method may return either void or Task.

– Source: http://nunit.org/index.php?p=releaseNotes&r=2.6.2

Are you serious?  I just happen to have the first version of NUnit that would properly handle async on my machine, but the build server was one notch older, and therefore couldn’t?  *facepalm*

To further prove that this was the real source of my issue, I installed NUnit 2.6.1 and 2.6.2 side by side on my machine.  I took my two tests from above, both of which should have tried to execute the MathLibrary.Divide function which included a 2-second delay:

    public class Math
    {
        public async Task<float> Divide(int Numerator, int Denominator)
        {
            await Task.Delay(2000);
            return Numerator / Denominator;
        }
    }

When I ran these two tests through NUnit 2.6.1, Divide_4DividedBy2_Equals2 completes in a couple hundredths of a second, while Divide_4DividedBy2_Equals2_Asynchrofied takes just over 2 seconds to complete, for a total of just over 2 seconds:

2-6-1

When I ran these through NUnit 2.6.2, EACH test takes just over 2 seconds to complete, for a total of just over 4 seconds:

2-6-2

So, I have two choices – switch my builds on TeamCity to use at least NUnit 2.6.2 to run the tests, or use Cleary’s Nito.AsyncEx library, which will allow me to leave the build server as is.  In any event, at least I have a reasonable explanation for what was happening. 

The funny thing is that it’s usually MSBuild that messes with me.  Apparently NUnit gave him the week off.

 


* Yes, I realize that by calling the service directly, this no longer counts as a "unit" test, but rather an integration test.  That distinction isn’t relevant to the issue described in this post, though, so I’m going to gloss over the mock objects in the real code.

Balloon Mapper

Our receiving station for the Stratoballoon project consisted of three major pieces of software:

I’ve gone into great depth about how the first two are configured on my technical blog (“Stratoballoon Radio Details”).  Today, I want to talk about the third one, BalloonMapper.  Here is the basic interface:

10

We would copy a dataline out of dl-fldigi and past it into the “Data Line” box (#1).  We could then hit Enter, or manually click the “Find Position” button in the upper right corner.  This would extract the altitude, and the lat/long from the data string.  It would convert the former into feet and display that in the “Altitude” box (#2).  It would also create the Google Maps URL that would show the lat/long as a pin on the map.

What did the data strings look like?  A picture-perfect data string that came off the radio would look like this:

KD8VZA-KD8VZA-KD8VZA,120057.00,234.11,4214.7460,8533.3750,*4FF4

This is a comma-delimited string, and is made up of the following:

  • My callsign, repeated 3 times
  • A timestamp, in hhmmss.xx format (where the decimal places are ignored)
  • The altitude, in meters
  • The latitude (format explained below)
  • The longitude (format explained below)
  • A termination string, made up of an asterisk, followed by four alphanumeric characters

In most cases the callsigns came out a bit garbled, so it would look more like this:

a8czZA-KD8VZA-KD8VZA,120057.00,234.11,4214.7460,8533.3750,*4FF4

The first part of the string got chewed up because it took us a second to tune dl-fldigi to lock onto the signal.  That’s the main reason I start the string with three copies – I wanted to give Katherine or I (whoever was working the radio) a second or two to get ahold of the signal.

Extracting the altitude was very straightforward.  Simply grab the 3rd piece of data in the string, multiple it by 3.28 to convert it from meters to feet, and display it in the box.

        public static String GetAltitude(String DataLine)
        {
            String[] DataLineComponents;
            String RawAltitude;

            DataLine = (DataLine ?? "").Trim();
            if (String.IsNullOrEmpty(DataLine)) { return ""; }

            DataLineComponents = DataLine.Split(',');

            RawAltitude = DataLineComponents[2];

            return String.Format("{0} ft", (double.Parse(RawAltitude) * 3.28).ToString("0"));
        }

The lat/long was a bit tricker.  First, I had to get them into a format that Google Maps would understand.  You can browse directly to a specific lat/long point on Google Maps like so:

https://www.google.com/maps/place/42°17’44.76″N+85°43’22.50″W

The lat/long values, however, always come off the radio in the 4-dot-4 pattern.  Here is how they broke down:

4214.7460 = 42° 14.7460′

8533.3750 = 85° 33.3750′

So, I would need to split the degrees from the rest of the string, then convert the fractional arc-minutes into arc-seconds, before I could drop it into Google Maps:

        public static String GetUrl(String DataLine)
        {
            String[] DataLineComponents;
            String RawLat, RawLong, FormattedLat, FormattedLong;

            DataLine = (DataLine ?? "").Trim();
            if (String.IsNullOrEmpty(DataLine)) { return ""; }

            DataLineComponents = DataLine.Split(',');

            RawLat = DataLineComponents[3];
            RawLong = DataLineComponents[4];

            FormattedLat = String.Format("{0}°{1}'{2}\"", RawLat.Substring(0, 2),
                                                          RawLat.Substring(2, 2),
                                                          (double.Parse(RawLat.Substring(4)) * 60).ToString("00.00"));
            FormattedLong = String.Format("{0}°{1}'{2}\"", RawLong.Substring(0, 2),
                                                           RawLong.Substring(2, 2),
                                                           (double.Parse(RawLong.Substring(4)) * 60).ToString("00.00"));

            return String.Format("https://www.google.com/maps/place/{0}N+{1}W", FormattedLat, FormattedLong);
        }

So, now I had my URL.  I needed a way to embed a browser into BalloonMapper, which was a Windows desktop app.  I looked at a few options, but eventually settled on Gecko Effects: https://bitbucket.org/geckofx/geckofx-29.0/downloads.

I created a Gecko.GeckoWebBrowser object on my form called “GoogleMaps”.  To browse to a URL, I simply called the .Navigate() method on the GoogleMaps object, and passed it the URL that I generated above:

                this.GoogleMaps.Navigate(GetUrl(this.DataLineBox.Text));

 

Using it was easy.  Getting the control installed and working was a little more difficult, and I had a few false starts.  In the end, here is what worked:

  • I downloaded Gecko Effects 29.0 (see link above).
  • Gecko requires another application called “xulrunner”, which I obtained from here: http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/29.0.1/runtimes/ .
  • I found that I needed to match the version of xulrunner to the version of Gecko, otherwise I got a “Specified cast is not valid” error.
  • I also found that the program has to be installed to a folder called “xulrunner” – all lowercase – or it wouldn’t work.

This made finding the capsule’s current location extremely easy:

20

For full source code and binaries, please visit http://TinyURL.com/MarkGilbertSource, and look for the BalloonMapper.zip archive.

Resisting the woodpeckers – Builder Pattern

If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
– (Gerald) Weinberg’s Second Law

A couple of months ago, I found a recommendation on my company’s intranet for "Growing Object-Oriented Software, Guided by Tests" by Steve Freeman and Nat Pryce.  I am an avid reader, but believe or not, I haven’t actually managed to read all the books yet, so I checked this one out from the library, and went through it. 

One of the real gems I found inside was a pattern I hadn’t seen before – the builder pattern (for those of you who have the book, this appears starting on page 258).  The goal here is to create data for a test in a way that keeps your test clean, but also gives you the flexibility to change that data when you need to.  It is also very expressive – you know exactly what part of the data is being changed just by reading the setup code.

Their example, which is what sold me on this pattern looks like this:

new AddressBuilder()
       .build();

This would get you a simple address, with (presumably) default, valid, values.  Next, the builder class would allow you to modify the defaults using methods like so:

new AddressBuilder()
       .withStreet("221b Baker Street")
       .withStreet2("London")
       .withPostCode("NW1 6XE")
       .build();

The methods withStreet(), withStreet2(), and withPostCode() would override the address 1, address 2, and postal code, respectively.  What’s more, this is far clearer than writing a method like UpdateTestData("221b Baker Street", “London”, "NW1 6XE") to do the same thing – is the second parameter modifying the street address or the city?  You no longer know at a glance, you now have to dig into the code to find out.

I’ve had to do things like this in the past numerous times, and my setup code for this has been wearisome-at-best to maintain.  Not only is this pattern clean and expressive, but it could start out simple and grow with my tests.  I could start out with the default case, and if I found that I later needed to test a case involving a custom postal code, I could add a method that allowed me to inject that value.  I wouldn’t have to touch any of my other tests, or do anything crazy with my setup logic – I would just have to add a method, and chain it for the one test that needed it.

I vowed that my next project would use this pattern, and in the last couple of weeks, I got the opportunity to put it to good use.  I was building a mechanism for NLog that would allow me to configure it from a database (rather than from web.config/app.config; I won’t go into detail on how this is done, but it turns out to be rather straightforward: https://github.com/nlog/NLog/wiki/Configuration-API ).  I would pass in a Dictionary of name-value pairs for the properties, and then I wanted to test that the proper NLog target and logger was configured (out of the gate I wanted to support a database target and a mail target).

After some back and forth – some of which was me getting comfortable with the pattern, and some of which was me letting the tests drive the functionality that I needed – I arrived at the following structure:

private class NLogSettingsBuilder
{
    private List<KeyValuePair<String, String>> _Settings;

    public NLogSettingsBuilder()
    {
        this._Settings = new List<KeyValuePair<String, String>>();
    }

    public NLogSettingsBuilder WithAllDatabaseSettings()
    {
        this._Settings = new List<KeyValuePair<String, String>>();
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.connectionStringName", "SomeName"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.commandText", "insert into EventLog ([Origin], [LogLevel], [Message], [StackTrace], SourceMachine) values (@origin, @logLevel, @message, @stackTrace, @sourceMachine);"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.name", "database"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.Parameter.origin", "Services"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.Parameter.logLevel", "${level:uppercase=true}"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.Parameter.message", "${message}"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.Parameter.stackTrace", "${stacktrace}"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Database.Parameter.sourceMachine", "${machinename}"));

        this._Settings.Add(new KeyValuePair<String, String>("Logger.Database.minlevel", "Error"));
        return this;
    }

    public NLogSettingsBuilder WithAllMailSettings()
    {
        this._Settings = new List<KeyValuePair<String, String>>();
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.name", "email"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.subject", "Blah Local Dev Error"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.to", "mgilbert@blah.com"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.from", "nlog@blah.com"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.smtpServer", "smtp.blah.com"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.encoding", "UTF-8"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.body", "Timestamp: ${longdate}${newline}Level: ${level:uppercase=true}${newline}Logger: ${logger}${newline}Machine Name: ${machinename}${newline}${newline}Message: ${message}${newline}${newline}Stacktrace: ${stacktrace}"));
        this._Settings.Add(new KeyValuePair<String, String>("Target.Mail.html", "true"));

        this._Settings.Add(new KeyValuePair<String, String>("Logger.Mail.minlevel", "Error"));
        return this;
    }

    public NLogSettingsBuilder WithoutSetting(String Key)
    {
        this._Settings.RemoveAll(setting => setting.Key == Key);
        return this;
    }

    public NLogSettingsBuilder WithThisSettingAltered(String Key, String NewValue)
    {
        this.WithoutSetting(Key);
        this._Settings.Add(new KeyValuePair<String, String>(Key, NewValue));
        return this;
    }

    public Dictionary<String, String> Build()
    {
        Dictionary<String, String> NewSettings = new Dictionary<String, String>();
        if (this._Settings != null)
        {
            foreach (KeyValuePair<String, String> CurrentPair in this._Settings) { NewSettings.Add(CurrentPair.Key, CurrentPair.Value); }
        }
        return NewSettings;
    }
}

That allowed me to test things like:

this._NLogSettings = (new NLogSettingsBuilder())

                               .Build();

The default case, where there are no properties configured, and therefore no NLog targets will be configured.

this._NLogSettings = (new NLogSettingsBuilder())

                               .WithAllDatabaseSettings()

                               .Build();

All of the correct database settings will be present, so I should expect the database target and logger to be configured.

this._NLogSettings = (new NLogSettingsBuilder())

                               .WithAllMailSettings()

                               .Build();

All of the correct mail settings will be present, so I should expect the mail target and logger to be configured.

this._NLogSettings = (new NLogSettingsBuilder())

                               .WithAllDatabaseSettings()

                               .WithoutSetting("Target.Database.connectionStringName")

                               .Build();

All of the correct database settings will be present except for "Target.Database.connectionStringName".  Since this is a required property, I should not expect the database target and logger to be configured.

this._NLogSettings = (new NLogSettingsBuilder())

                               .WithAllDatabaseSettings()

                               .WithThisSettingAltered("Target.Database.connectionStringName", "Blah")

                               .Build();

All of the correct database settings will be present, and "Target.Database.connectionStringName" will have the value of "Blah".  I should not expect the database target and logger to be configured, and I should be able to test the connectionStringName property and confirm that its value matches "Blah".

As I said before, as soon as I read this, I was hooked.  I’ve struggled in the past to keep my test data manageable, and have had to bit a lot of bullets to make sweeping changes to keep it up to date.  This kind of pattern will help that immensely, and will go a great way, I think, to keeping the digital woodpeckers at bay.

Reducing the Tedium: Redux

Back in July, I wrote “Reducing the Tedium: Generalized Unit Tests via Reflection” which introduced a generalized unit test for strings and IDs in a pre-defined list of classes.  This was my first stab at trying to automate some of the more tedious tests I typically write for properties of this sort.  With my latest project, I was able to extend this even further with a new “PropertyValidator” class.

My first task was to eliminate the need for the explicit “TypesToCheck” array that defined which classes to test.  Since a lot of my use cases was checking business classes in the same assembly, I started by building a method that could take the name of the assembly to test as a parameter, open that assembly up via Reflection, and find all of the classes in it.

I started by repackaging my original code into two main functions – one for validating strings:

private static void ValidateStrings(Type CurrentType)
{
    String TestValue, ClassName;
    PropertyInfo[] ClassProperties;
    Object ClassInstance;
    
    ClassName = CurrentType.Name;
    ClassProperties = CurrentType.GetProperties().Where(p => p.PropertyType == typeof(String) && p.GetSetMethod() != null).ToArray();
    ClassInstance = Activator.CreateInstance(CurrentType);

    foreach (var PropertyUnderTest in ClassProperties)
    {
        if (ShouldSkipProperty(PropertyUnderTest)) { continue; }

        TestValue = (String)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.IsEmpty(TestValue, String.Format("{0}.{1} did not initialize properly", ClassName, PropertyUnderTest.Name));

        PropertyUnderTest.SetValue(ClassInstance, null, null);
        TestValue = (String)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.IsEmpty(TestValue, String.Format("{0}.{1} did not handle null properly", ClassName, PropertyUnderTest.Name));

        PropertyUnderTest.SetValue(ClassInstance, "", null);
        TestValue = (String)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.IsEmpty(TestValue, String.Format("{0}.{1} did not handle an empty string properly", ClassName, PropertyUnderTest.Name));

        PropertyUnderTest.SetValue(ClassInstance, "  ", null);
        TestValue = (String)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.IsEmpty(TestValue, String.Format("{0}.{1} did not handle a blank string properly", ClassName, PropertyUnderTest.Name));

        PropertyUnderTest.SetValue(ClassInstance, "abc123", null);
        TestValue = (String)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.AreEqual("abc123", TestValue, String.Format("{0}.{1} did not handle a valid string properly", ClassName, PropertyUnderTest.Name));
    }
}

 

And the other for validating IDs:

private static void ValidateIDs(Type CurrentType)
{
    long TestValue;
    String ClassName;
    PropertyInfo[] ClassProperties;
    Object ClassInstance;

    ClassName = CurrentType.Name;
    ClassProperties = CurrentType.GetProperties();
    ClassInstance = Activator.CreateInstance(CurrentType);

    foreach (var PropertyUnderTest in ClassProperties.Where(p => IsIDToValidate(p)))
    {
        if (PropertyUnderTest.GetCustomAttributes(typeof(ObsoleteAttribute), true).Count() > 0) { continue; }

        TestValue = (long)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.AreEqual(0, TestValue, String.Format("{0}.{1} did not initialize properly", ClassName, PropertyUnderTest.Name));

        PropertyUnderTest.SetValue(ClassInstance, 0, null);
        TestValue = (long)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.AreEqual(0, TestValue, String.Format("{0}.{1} did not handle being set to 0 properly", ClassName, PropertyUnderTest.Name));

        PropertyUnderTest.SetValue(ClassInstance, -1, null);
        TestValue = (long)PropertyUnderTest.GetValue(ClassInstance, null);
        Assert.AreEqual(0, TestValue, String.Format("{0}.{1} did not handle being set to a negative properly", ClassName, PropertyUnderTest.Name));
    }
}

 

These do the same basic checks on each string or ID property as described in the July post.  They make use of three helper functions – ShouldSkipType, ShouldSkipProperty, and IsIDToValidate.  I’ll describe these in turn:

private static bool ShouldSkipType(Type CurrentType)
{
    return CurrentType.GetCustomAttributes(typeof(PropertyValidator.Attributes.DoNotPerformBasicValidation), true).Length > 0 
        || CurrentType.IsGenericType 
        || CurrentType.IsAbstract
        || CurrentType.FullName.StartsWith("PostSharp");
}

The ShouldSkipType function returns True if the class:

  • is a generic type
  • is an abstract type
  • starts with “PostSharp” (this is a logging library that I started using this summer, and its classes are added to mine post-build; trying to run my test code against these classes cause problems, so I just skip them entirely)
  • has the custom “DoNotPerformBasicValidation” attribute attached.

If any of these conditions is met, the class is skipped.  I found a need to create exceptions to the rule of “check every class in this assembly”, so I created the “DoNotPerformBasicValidation” attribute that I could decorate a specific class in an assembly to be skipped.  This attribute has no logic of its own – it is merely used as a flag on the class:

using System;
using System.Collections.Generic;
using System.Linq;

namespace PropertyValidator.Attributes
{
    [AttributeUsage(AttributeTargets.All)]
    public class DoNotPerformBasicValidation : Attribute 
    { 
    }
}

This attribute can be applied to not only classes, but also individual properties, and the ShouldSkipProperty function looks for that:

private static bool ShouldSkipProperty(PropertyInfo CurrentProperty)
{
    return CurrentProperty.GetCustomAttributes(typeof(PropertyValidator.Attributes.DoNotPerformBasicValidation), true).Length > 0;
}

This function returns True if the custom attribute is found on the current property being evaluated.

Finally, to determine if a given property is a string, “ValidateStrings” merely looks at the property’s type.  To determine if it is an ID to be checked is a little trickier.  I can’t rely solely on its base type, so instead I require that property to be treated as an ID is marked as such, with another custom attribute:

using System;
using System.Collections.Generic;
using System.Linq;

namespace PropertyValidator.Attributes
{
    [AttributeUsage(AttributeTargets.Property)]
    public class ValidateAsID : Attribute 
    {
    }
}

When the “ValidateAsID” attribute is applied to a property, the “IsIDToValidate” function returns true:

private static bool IsIDToValidate(PropertyInfo CurrentProperty)
{
    return CurrentProperty.GetCustomAttributes(typeof(PropertyValidator.Attributes.ValidateAsID), true).Length > 0;
}

 

The “ValidateStrings” and “ValidateIDs” functions need a list of classes to open and examine.  That list is provided by the PropertyValidator’s “Validate” methods:

public static void Validate(String AssemblyPartialName)
{
    Validate(AssemblyPartialName, null);
}
public static void Validate(String AssemblyPartialName, String ClassName)
{
    Assembly AssemblyToValidate;
    Type[] AssemblyTypes;

    AssemblyToValidate = Assembly.Load(AssemblyPartialName);
    if (AssemblyToValidate == null) { throw new Exception(String.Format("Could not load {0}", AssemblyPartialName)); }

    AssemblyTypes = AssemblyToValidate.GetTypes();

    foreach (Type CurrentType in AssemblyTypes)
    {
        try
        {
            if (ShouldSkipType(CurrentType)) { continue; }
            if (ClassName != null && CurrentType.Name != ClassName) { continue; }

            System.Diagnostics.Trace.WriteLine(String.Format("Now testing '{0}'", CurrentType.Name));

            ValidateStrings(CurrentType);
            ValidateIDs(CurrentType);
        }
        catch (Exception ex)
        {
            throw new Exception(String.Format("Error validating the type '{0}'", CurrentType.Name), ex);
        }
    }
}

The first takes only the assembly name, and will attempt to check every class in that assembly.   The second will allow you to check a single specific class in an assembly.  For each class being checked, then, the method will invoke both “ValidateStrings” and “ValidateIDs”.

To use it, then, I can do something as simple as

PropertyValidator.Validate(“MyAssembly”);

or

PropertyValidator.Validate(“MyAssembly”, “MyClass”);

***

PropertyValidator gives me a much better testing framework for properties than before, and is very easy to use.  I still have a dependency on NUnit, however, and it doesn’t do anything with other data types such as datetimes.  Perhaps the next iteration.

Now you see it, now you… still see it? Hiding Inherited Properties

A while ago, a colleague of mine, Doug, and I got into a conversation about inherited properties, and the potential for hiding them.  The precise scenario we were looking at was a base class with a "public” property, and a child class that descends from it with the same property redefined as "private".  We weren’t sure if we could do this at all, and even if we could, was it a good idea?  We ended up going a different way for the problem we were working on, but the conversation stuck in my head and I decided that I would look into it more when I had the chance.

Let’s start by defining a very simple base class:

    public class BaseClass
    {
        public String StringProperty { get; set; }
    }

And then define a child class to descend from it:

    public class ChildClass : BaseClass
    {
    }

Now, we’ll add a new version of "StringProperty", and let’s begin by keeping the scope the same:

    public class ChildClass : BaseClass
    {
        public new String StringProperty { get; set; }
    }

Next, let’s have ChildClass initialize "StringProperty" with a value:

    public class ChildClass : BaseClass
    {
        public new String StringProperty { get; set; }

        
        public ChildClass()
        {
            this.StringProperty = "INITIALIZED By Child";
        }
    }

Now, let’s write a small program that instantiates ChildClass, and reassigns "StringProperty":

    class Program
    {
        static void Main(string[] args)
        {
            ChildClass MyChildClass = new ChildClass();

            Console.WriteLine("Initialized:\t{0}", MyChildClass.StringProperty);
            MyChildClass.StringProperty = "ASSIGNED By Program";
            Console.WriteLine("Assigned:\t{0}", MyChildClass.StringProperty);

            Console.ReadLine();
        }
    }

As soon as I compile this, I’ll get a warning:

‘ParentChildProperties.ChildClass.StringProperty’ hides inherited member ‘ParentChildProperties.BaseClass.StringProperty’. Use the new keyword if hiding was intended.

(Let me point out a little grammatical issue here.  When I read this, my first question, “Ok, what’s the new keyword I’m supposed to use?”  What they meant was that the keyword to use is literally “new”.  That should have been enclosed in quotation marks in the above message.")

A little research turns up a couple of MSDN articles talking about this warning, and the larger topic of "hiding" inherited properties:

  1. http://msdn.microsoft.com/en-us/library/aa691135(v=vs.71).aspx
  2. http://msdn.microsoft.com/en-us/library/vstudio/435f1dw2.aspx

Adding the "new" modifier sounds like it only suppresses the warning, and doesn’t actually change the behavior of the properties, but let’s test that, too.

Scenario 1 – Same scopes, no "new" modifier

When I run the application built so far, I get the following output:

Scenario 1

The property is initialized and assigned as I would expect it.  Furthermore, when I inspect the initialized version of the property in the Visual Studio debugger, I see that ChildClass.StringProperty has the initialized value, but BaseClass’s version is null.  When I inspect the assigned value, ChildClass.StringProperty now has the assigned value, and the BaseClass version is still "null".

Scenario 2 – Scope is narrowed, no "new" modifier

If I change ChildClass.StringProperty to be "private", thus narrowing the scope of the property, this is the output:

Scenario 2

When I inspect the initialized value, the ChildClass and BaseClass properties are exactly the same as they were in Scenario 1, but this time the initialized value doesn’t get printed.  Once I assign a new value to it, that assigned value is printed out.  However, when I inspect StringProperty, I find that the ChildClass version still has the initialized value, but BaseClass’s version now has the assigned value.

Scenario 3 – Same scopes, added the "new" modifier

When I add the "new" modifier to ChildClass.StringProperty, and change the scope back to "public", I get the exact same results as Scenario 1.  This seems to confirm that the “new” modifier doesn’t change behavior – it only suppresses a warning.

Scenario 4 – Scope is narrowed, added the "new" modifier

When I changed the scope to "private" again, I get the exact same results as Scenario 3.  Again, this seems to confirm that the “new” modifier doesn’t change behavior.

 

So what’s going on here?  I believe this line from the first MSDN article explains it:

A declaration of a new member hides an inherited member only within the scope of the new member.

In this case, the new member’s scope is ChildClass.  When I declare "StringProperty" to be private, and then tried to access it from the program (now outside the scope of ChildClass), it couldn’t find that version, so it fell back to using on the base class version.  Since that version is never assigned, the program can only print out the "null". 

How do we explain what we were seeing through the debugger?  The debugger has always been able to inspect the full properties of a class – regardless of their scopes – so that’s why it can show me the assigned values properly every time.  However, assigning MyChildClass.StringProperty, then, must actually assign the base class version of this property, and it’s the base class version that is printed – not ChildClass’s version.

As the second article describes, this is really not so much "hiding" as it is "replacing".  That sends me back to the original question.  Is there a way to truly hide a base class property, so that it doesn’t even show up in Intellisense?

Jon Skeet responded to this exact question on a forum post on Bytes.com in 2006.  In short, no, this is not allowed:

…However, you can’t hide them in terms of preventing people from calling them. Doing so would violate Liskov’s Substitution Principle – you should always be able to treat a derived type as the base type.

***

So, the technique of hiding a property I think will be related to my "use sparingly" bucket.

Furthermore, while narrowing the property’s scope in the child class is allowed by the language, it

  1. makes things harder to troubleshoot
  2. will downright mislead me when I’m inspecting properties in the debugger
  3. seems unfit for any real-world scenario

QED – Narrowing scope is bad and should be avoided.

Breaking the Mold – Hacking together an Interface for Constants

It seems like once a project gets to a certain size, magic strings – that is, character values hard-coded into the application – become inevitable.  When a piece of software needs to read data generated by another piece of software, the use of magic strings becomes a requirement for sanity.  The common pattern for dealing with magic strings is to encapsulate them in a constant:

        public const String FRUITS_APPLE = "Apple";

That works fine when you have a small number of constants, but what happens when you have 10, 20, or more?  Furthermore, what do you do when subsets of them are logically related to each other?  One approach is to name them according to that logical group:

        public const String APPLES_RED_DELICIOUS = "Red Delicious";
        public const String APPLES_GALA = "Gala";
        public const String APPLES_FUJI = "Fiji";

        public const String ORANGES_BLOOD = "Blood";
        public const String ORANGES_NAVEL = "Navel";
        public const String ORANGES_VALENCIA = "Valencia";

        public const String LEMONS_MEYER = "Meyer";
        public const String LEMONS_EUREKA = "Eureka";
        public const String LEMONS_LISBON = "Lisbon";

What I’d really prefer to do is to create enumerations for each of these groups.  The problem is an enumeration can’t have string values behind it:

        public enum Apples
        {
            RedDelicious = "Red Delicious",
            Gala = "Gala",
            Fuji = "Fuji"
        }

This will return a compile-time error of "Cannot implicitly convert type ‘string’ to ‘int’".

I’ve gotten around this in the last few years by creating one or more subclasses, one for each logical grouping, and then creating constants within.  I call these "constants-classes":

        public class Apples
        {
            public const String RedDelicious = "Red Delicious";
            public const String Gala = "Gala";
            public const String Fuji = "Fiji";
        }
        public class Oranges
        {
            public const String Blood = "Blood";
            public const String Navel = "Navel";
            public const String Valencia = "Valencia";
        }
        public class Lemons
        {
            public const String Meyer = "Meyer";
            public const String Eureka = "Eureka";
            public const String Lsibon = "Lisbon";
        }

In code, then, I can access these values just like I would the values of a true enumeration:

        String CurrentApple = Apples.RedDelicious;
        String CurrentOranage = Oranges.Navel;

This pattern has served me well over the years, but I ran into a new challenge with it in my current project.  The application imports XML messages pulled off of a queue, and there are a small number of major types of entities that need to be processed.  (For the purposes of this post, I’ll continue my fruit analogy and say that the types of entities are apples, oranges, and lemons; I’m not really writing a fruit app.)

Large chunks of the XML for these different types are actually the same, so I built a series of System.Xml.Linq.XElement extension methods that operate on a specific slice of the XML.  When I import a given entity – let’s say a lemon – I break off the appropriate piece of the full XML document for that lemon, then call the appropriate extension method to de-serialize it and turn it into a strongly-typed object (“FruitProperties” in this case):

        public static FruitProperties ExtractProperties(this XElement XmlToProcess)
        {
        }

The XML was largely made up of collections of <Attribute /> blocks, each of which contained the same basic components.  One of these components was the "name" of the attribute – a unique handle that will never change, and allows me to safely identify the various bits of data for an entity.  I defined several constants-classes to centralize these names. 

Let’s say I had attributes like "PeelTexture", "Color", and "HasSeeds".  The challenge arose when I realized that although all of my entity types had these attributes, the actual attribute names used in the apple-XML versus the orange-XML were different.  For example, the PeelTexture attribute might appear as "Peel_Texture" for an apple, but "Orange_Peel" for an orange.   
   
My first attempt to address this was to try to move the constants to an “IFruit” interface.  My thought was to define the template for the constants, and then I would "implement" them (assign the real, apple-, orange-, and lemon-specific values) in the concrete classes that implemented that interface.  However, I got another compile-time error because C# (and presumably all .NET languages) don’t allow interfaces to have static members, fields, or properties.

I tried several other approaches before I arrived at this slightly-hacky solution.  First, I defined my constants-classes to hold all of my entities’ unique values:

        public class Constants
        {
            public class Apple
            {
                public const String PeelTexture = "Peel_Texture";
                public const String Color = "Color";
                public const String HasSeeds = "Apple_HasSeeds";
            }
            public class Orange
            {
                public const String PeelTexture = "Orange_Peel";
                public const String Color = "Orange_Color";
                public const String HasSeeds = "Has_Seeds";
            }
            public class Lemon
            {
                public const String PeelTexture = "PeelTexture_2";
                public const String Color = "Color_Lemon";
                public const String HasSeeds = "Has_Any_Seeds";
            }
        }

I then modified my generic ExtractProperties method to take a Type object.  This object would be the actual constants-class for the entity being processed:

        public static FruitProperties ExtractProperties(this XElement XmlToProcess, Type FruitConstants)
        {
        }

This method would be invoked as follows:

        XDocument MyDocument;
        FruitProperties MyProperties;

        // Load XML into MyDocument here

        XElement SliceToImport = MyDocument.Element("Root").Element("Properties");
        MyProperties = SliceToImport.ExtractProperties(typeof(Constants.Apple));

Within the ExtractProperties method, I then naively tried to do this to get the actual value of the constant:

        String FieldToExtract = FruitConstants.PeelTexture;

But ExtractProperties had no idea what "FruitConstants" type really was, so this also throws a compile-time error.  So, I then created a simple enumeration that became my "template" for my constants-classes.  This enumeration’s members would have the same name as the constants defined in my classes:

        public enum FruitConstantsTemplate
        {
            PeelTexture,
            Color,
            HasSeeds
        }

I could use that template – and a little trust – to pull the desired value out of the constants-class by its name using reflection.  I wrote a custom function to do just that:

        public static String GetFieldName(Type T, String ConstantName)
        {
            FieldInfo CandidateConstant;

            // Validate the parameters being passed in
            ConstantName = (ConstantName ?? "").Trim();
            if (String.IsNullOrEmpty(ConstantName)) { throw new ConstantException(); }

            if (T == null) { throw new ClassException(); }

            // Get the list of constants from type T using reflection
            var Constants = T.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);

            // Find the one I'm looking for, based on name.
            CandidateConstant = Constants.FirstOrDefault(c => c.Name == ConstantName);
            if (CandidateConstant == null) { throw new ConstantNotFoundException(ConstantName, T.Name); }
            return (String)CandidateConstant.GetValue(CandidateConstant);
        }

I modified ExtractProperties to use this new function:

            String FieldToExtract = GetFieldName(typeof(Constants.Apple), FruitConstants.PeelTexture.ToString());

I say "a little trust" because this function only returns a constant’s value if both of the following hold true:

  1. the FruitConstantsTemplate defines it; and
  2. the constants-class passed in as type T contains it

This sort of thing is what an interface would enforce for methods (for example) at compile-time.  With this approach, however, there’s nothing to stop me from adding a value to the enumeration, and forgetting to add it to the constants-classes (or vice versa).  There’s also nothing at compile time to stop me from passing in a completely invalid type to GetFieldName(), such as "String" or "DateTime" (again, something a true interface would catch at compile-time).

This approach does have its share of advantages, though:

  1. It allows me to concentrate the "generic-ness" in one function (rather than having the same basic logic duplicated in several functions, differing only by the constants it was using).
  2. It also allows me to define and continue using the class-constants just as I have always done.  The only catch is when I add a constant, I have to remember to update the template with it.

***

While I have a functional solution, I also have a nagging thought.  This is organic solution, grown (no pun intended) around the constraints of the framework and the language, but is there a better way to accomplish what I’m trying to do?

A question to revisit for my next project.

Queue them up! Unit testing HttpClient

Early in my current project, I was looking for a way to test some logic that relied on HttpClient.PostAsync.  I was writing a routine that would process items coming off a queue that was exposed via a series of REST services.  Subscribing to the queue, pulling messages down, and cleaning the subscription up once the queue was empty all required calls to the services, and in most cases several calls.  Ideally I’d be able to mock the calls to HttpClient.PostAsync out, but I can’t because that method isn’t virtual.  The usual way to handle methods like that is to build an interface that I CAN mock out, and then build a wrapper-implementation of that interface which calls HttpClient.PostAsync.  My unit tests would use a mock of that interface, and the real code would use my wrapper.  Adding interfaces adds flexibility to a piece of software, at the cost of readibility and maintainability, so before I went that route I wanted to see if there was a better way.

I came across this post by Gabriel Perez where he shows how to build a fake handler that returns an “injected” response when PostAsync is invoked.  (He credits Glenn Bock for the original source.)  This “russian doll model” as he calls it looked very promising.  In fact, I thought I could even extend it to inject the responses from a queue, allowing me to line them for a specific scenario, and then test my code against it.

I decided that a simple list would suffice for the queue.  FakeHandler would just keep track of which responses it had already handed out:

// FakeHandler, adapted from: http://perezgb.com/2012/02/21/web-api-testing-with-httpclient
        public class FakeHandler : DelegatingHandler
        {
            public List<HttpResponseMessage> Responses { get; set; }
            private int _Index;
public FakeHandler() : base()
            {
                this.Responses = new List<HttpResponseMessage>();
                this._Index = -1;
            }

            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
this._Index++;
                if (this._Index >= this.Responses.Count) { return Task.Factory.StartNew(() => (HttpResponseMessage)null); }
                return Task.Factory.StartNew(() => Responses[this._Index]);
            }
        }

Here is how a test would look using this structure:

        [Test]
        public void SomeTest()
        {
            HttpResponseMessage ConfiguredResponse;
            HttpClient ConfiguredClient;
            FakeHandler NewHandler;
            QueueProcessor MyProcessor;

            // Configure the response.  Set properties (headers, etc.) as needed.
            ConfiguredResponse = new HttpResponseMessage();

            // Build a handler around this response
            NewHandler = new FakeHandler() { InnerHandler = new HttpClientHandler() };
            NewHandler.Responses.Add(ConfiguredResponse);

            // Create a client object around this handler
            ConfiguredClient = new HttpClient(NewHandler);

            // Pass in the pre-configured client to the class under test (dependency injection)
            MyProcessor = new QueueProcessor(ConfiguredClient);

            // Test the method
            var Results = MyProcessor.DoSomething();

            // TODO: Evaluate the results
        }

For “real” use, I would simply pass in a new HttpClient() object to the QueueProcessor constructor.  This all worked quite well to mock out the responses, but my tests could only evaluate what came out at the very end.  I also wanted to make sure the individual responses were being handled properly.

I could have simply injected a set of Asserts into FakeHandler.SendAsync, but I wanted to build it so it could potentially handle completely different tests each time.  To do that, I added an event handler called “OnEntryVerificationMethod”.  This became a property of the FakeHandler class that I could define in my unit test, which would be run at a known point in the execution (on entry), and would have access to both the current and previous responses (see bolded additions below).

// Define the prototype for the delegate that will perform our validation
        public delegate void VerifyOnEntry(HttpRequestMessage CurrentRequest, HttpResponseMessage PreviousResponse);

        // FakeHandler, adapted from: http://perezgb.com/2012/02/21/web-api-testing-with-httpclient
        public class FakeHandler : DelegatingHandler
        {
            public List<HttpResponseMessage> Responses { get; set; }
            private int _Index;

            // Define a delegate that allows me to pass in a custom function at runtime
            public VerifyOnEntry OnEntryVerificationMethod;

            public FakeHandler() : base()
            {
                this.Responses = new List<HttpResponseMessage>();
                this._Index = -1;
            }

            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                // If a custom function was defined, invoke it, passing in the parameters to be verified.
                if (OnEntryVerificationMethod != null)
                {
                    OnEntryVerificationMethod(request, (this._Index < 0 ? (HttpResponseMessage)null : Responses[this._Index]));
                }

                this._Index++;
                if (this._Index >= this.Responses.Count) { return Task.Factory.StartNew(() => (HttpResponseMessage)null); }
                return Task.Factory.StartNew(() => Responses[this._Index]);
            }
        }

I could define this in my unit test using an anonymous function:

            int NumberOfMessagesProcessed = 0;
            NewHandler.OnEntryVerificationMethod = (CurrentRequest, PreviousResponse) =>
            {
                NumberOfMessagesProcessed++;

                if (PreviousResponse == null) { return; }

                switch (NumberOfMessagesProcessed)
                {
                    case 1:
                        // TODO: Perform tests for the first response processed
                        break;

                    case 2:
                        // TODO: Perform tests for the second response processed
                        break;
                }
            };

Now I had a window into FakeHandler’s execution, and could inspect anything I needed.

If HttpClient.PostAsync was virtual (and therefore directly mockable), it would have made testing one call far easier, but trying to simulate multiple calls in a row would probably have pushed me into this structure anyway.

You could argue that in lining up multiple responses like this I’m trying to test too much; that what I should be doing is setting up everything for a given scenario (e.g., responses have already come back as “fail” twice), and then pass in the one I really want to test (the third attempt is a success).  However, I think that would result in a more complicated code base because I would have to make several internal properties available to my test (like the number of times an HttpClient.PostAsync call results in a failure), or make more extensive use of interfaces, or both.  Lining up a series of responses, and then testing that greater scenario, is a more straightforward approach.

Sometimes, I will totally trade having code that is awesomely-flexible and unit test-pure for code that I can more easily get my head wrapped around.

Now where did I put that day? .NET Date Math, and Reversibility

This past week, I hit an interesting quirk with dates in .NET (or possibly it’s a quirk with the Gregorian calendar).  I started by subtracting 6 months from "today" to get a new date, and then later would add 6 months back to make sure I would get "today" again.  This scenario was part of a very simple unit test that I had written weeks ago, and had been passing fine for all of that time.

That is, until "today" was 8/29/2013.  On that day, my test failed.

If "today" were 8/15/2013, then subtracting 6 months would yield 2/15/2013 – just what I’d expect;

            DateTime InitialDate, NewDate;
            InitialDate = DateTime.Parse("8/15/2013");
            NewDate = InitialDate.AddMonths(-6);
            // NewDate will be 2/15/2013

However, if I started with 8/29/2013, there’s a snag:

            DateTime InitialDate, NewDate;
            InitialDate = DateTime.Parse("8/29/2013");
            NewDate = InitialDate.AddMonths(-6);
            // NewDate will be 2/28/2013

There is no 29th day of February in 2013, so to return a valid date .NET returns 2/28/2013 instead.  What happens when I add 6 months to 2/28/2013?

            DateTime InitialDate, NewDate;
            InitialDate = DateTime.Parse("2/28/2013");
            NewDate = InitialDate.AddMonths(6);
            // NewDate will be 8/28/2013

I get 8/28/2013 – not what I originally started with.  I actually end up losing a day due to the equivalent of a rounding error for calendars.

What if I were to go in the other direction originally – start with 8/29/2013 and ADD 6 months?

            DateTime InitialDate, NewDate;
            InitialDate = DateTime.Parse("8/29/2013");
            NewDate = InitialDate.AddMonths(6);
            // NewDate will be 2/28/2014

As before, since February 2014 has no 29th day, .NET gives me the next oldest day – the 28th.

The lesson here is that date-math using MONTHS is not always a reversible operation.  If I were to switch to adding and subtracting DAYS, however, that appears to be reversible:

            DateTime InitialDate, NewDate;
            InitialDate = DateTime.Parse("8/29/2013");
            NewDate = InitialDate.AddDays(-183).AddDays(183);
            // NewDate will be 8/29/2013

This isn’t limited to February, either.  Any time my starting month has more days than the month I end up with, this will happen (for example, October and April, December and June).

Ah, fun with dates.