Easily Test Your Code For Multiple Cultures

code, tdd 0 comments suggest edit

Globe from the
stock.xchng Most of the time when I’m testing my code, I only test it using the en-US culture since, …well…, I speak English and I live in the U.S. Isn’t the U.S. the only country that matters anyway? ;)

Fortunately, there are Subtext team members living in other countries ready to smack such nonsensical thoughts from my head and keep me honest about Localization and Internationalization issues.

Simone, who is an Italian living in New Zealand, pointed out that a particular unit test that works on my machine always fails on his machine. Here’s the test.

[RowTest]
[Row("4/12/2006", "04/12/2006 00:00:00 AM")]
[Row("20070123T120102", "01/23/2007 12:01:02 PM")]
[Row("12 Apr 2006 06:59:33 GMT", "04/12/2006 06:59:33 AM")]
[Row("Wed, 12 Apr 2006 06:59:33 GMT", "04/12/2006 06:59:33 AM")]
public void CanParseUnknownFormatUTC(string received, string expected)
{
  DateTime expectedDate = DateTimeHelper.ParseUnknownFormatUTC(received);
  Assert.AreEqual(expected, expectedDate.ToString("MM/dd/yyyy HH:mm:ss tt"));
}

The method being tested simply takes in a date string in an unknown format and performs a few heuristics in order to parse the date.

The way I test this method is very U.S. centric. I call ToString() and then match it to the expected string defined in the Row attributes (I can’t use actual DateTime values in the attributes).

So for the very first row, I expect that date to match 04/12/2006 00:00:00 AM. But when Simo runs the test over there in New Zealand, he gets12/04/2006 00:00:00 a.m.

Makes you wonder how anyone over there can keep an appointment with the month and date all backwards like that. ;)

Testing In Another Culture

At this point, I start thinking of convincing my wife to take a vacation in New Zealand so I can test this method properly. Hmmm… that’s probably not going to fly, with the newborn and all.

Another option is to go into my regional settings and change my locale to test temporarily, but that sort of defeats the purpose of automated tests once I change it back. What to do?

MbUnit to the rescue!

Once again, I discover a feature I hadn’t known about in MbUnit that solves this problem (Jeff and Jon, feel free to snicker).

Looking at the MbUnit TestDecorators page, I noticed there is a [MultipleCultureAttribute] decorator! Hmmm, I bet that could end up being useful.

Unfortunately, at the time, this decorator was not documented (I’ve since documented it), so I looked up the code on Koders real quick to see the documentation and saw that I simply need to pass in a comma delimited string of cultures. This allows me to run a single test multiple times, once for each culture listed.

Here is the updated test with my code correction.

[RowTest]
[Row("4/12/2006", "04/12/2006 00:00:00 AM")]
[Row("20070123T120102", "01/23/2007 12:01:02 PM")]
[Row("12 Apr 2006 06:59:33 GMT", "04/12/2006 06:59:33 AM")]
[Row("Wed, 12 Apr 2006 06:59:33 GMT", "04/12/2006 06:59:33 AM")]
[MultipleCulture("en-US,en-NZ,it-IT")]
public void CanParseUnknownFormatUTC(string received, string expected)
{
  DateTime expectedDate = DateTimeHelper.ParseUnknownFormatUTC(received);
  Assert.AreEqual(DateTime.ParseExact(expected
    , "MM/dd/yyyy HH:mm:ss tt"
    , new CultureInfo("en-US")), expectedDate);
}

One cool note about how decorators like this work in MbUnit is the way it composes with the RowTest’s Row attributes. For example, in the above test, the test method will get called once per culture per Row for a grand total of 12 times.

So now my friends in faraway places will have the pleasure of unit tests that pass in their respective locales and I can feel like a better citizen of the world.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

11 responses

  1. Avatar for Simone Chiaretta
    Simone Chiaretta June 14th, 2007

    If you come NZ maybe you will not find me... better for you to fly to Italy :)

  2. Avatar for Simone Chiaretta
    Simone Chiaretta June 14th, 2007

    BTW: we could decorate also all other culture sensitive tests with this attribute... there are a lot of date processing, especially in the RSS classes

  3. Avatar for Damien Guard
    Damien Guard June 14th, 2007

    Some programmers just love to use basic types like strings. Fowler fingers this as a code smell he calls "Primitive obsession".
    Like all types you should keep it in it's own type for as long as possible. When it has to be passed to something that won't deal with your objects, e.g. a HTML stream, then .ToString at the last moment. When dealing with incoming data .Parse at the first available opportunity.
    I've never understood the logic behind the US date format - perhaps you can clarify it for the rest of us?
    dd-mm-yyyy makes sense as the days turn into months which turn into years. yyyy-mm-dd make sense from a sorting perspective but mm-dd-yyyy... What's that all about?
    [)amien

  4. Avatar for Haacked
    Haacked June 14th, 2007

    It's not that I want to use strings for the dates, I have to because attributes are compile time and I can't put in a runtime value such as a datetime as a value to the row attribute.

  5. Avatar for James McKay
    James McKay June 14th, 2007

    It's time you Americans learned how to get the date right, spell words like "colour" correctly and to pronounce "tomato" the way God intended. And why do you drive on the wrong side of the road? :)
    Seriously, can't you use a culture invariant format for dates and times? "yyyy-MM-dd HH:mm:ss" (24 hour, no days of the week, numeric months, no am/pm nonsense etc) should do the trick.

  6. Avatar for Haacked
    Haacked June 14th, 2007

    @James - Well I'm receiving the date as input, so I have no idea what format it will be in, hence the point of the method. But that's tangential to the point of this post. ;)

  7. Avatar for The Other Steve
    The Other Steve June 14th, 2007

    I thought you were going to show me how MbUnit had a way to translate my page to insure I did the localization correctly for the labels. :-)

  8. Avatar for Jonathan de Halleux
    Jonathan de Halleux June 15th, 2007

    I wrote that attribute a while ago :) If you look closely in MbUnit, you'll also see the PelikhanAttribute...

  9. Avatar for Christopher Steen
    Christopher Steen June 18th, 2007

    Tip/Trick: Creating Packaged ASP.NET Setup Programs with VS 2005 [Via: ScottGu ] Calling an ASMX webservice...

  10. Avatar for Scott
    Scott June 18th, 2007

    Mate, if you come to NZ, I'll buy you a beer (we've got some good ones). Your blog is definitely worth it. Keep up the good work.
    Oh and for all the naysayers about the US date, if it works for them... And just be glad we aren't using that gregorian calendar thing with all those crazy months, oh, we are...

  11. Avatar for Robbie
    Robbie June 26th, 2007

    About the US date format, I live here and logically, the rest of the world is right. Although why the rest of the English speaking world spells color wrong is beyond me. ;)
    BTW, does anybody have any localization tool recommendations? I'm considering springing for a copy of Lingobit Localizer for a project I'm working on, but wanted to know if anybody knew of cheaper / better alternatives?