Easily Test Your Code For Multiple Cultures

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 gets 12/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.

What others have said

Requesting Gravatar... Simone Jun 14, 2007 11:40 PM
# re: Easily Test Your Code For Multiple Cultures
If you come NZ maybe you will not find me... better for you to fly to Italy :)
Requesting Gravatar... Simone Jun 15, 2007 12:04 AM
# re: Easily Test Your Code For Multiple Cultures
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
Requesting Gravatar... Damien Guard Jun 15, 2007 1:01 AM
# re: Easily Test Your Code For Multiple Cultures
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
Requesting Gravatar... Haacked Jun 15, 2007 1:11 AM
# re: Easily Test Your Code For Multiple Cultures
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.
Requesting Gravatar... James McKay Jun 15, 2007 1:35 AM
# re: Easily Test Your Code For Multiple Cultures
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.
Requesting Gravatar... Haacked Jun 15, 2007 2:04 AM
# re: Easily Test Your Code For Multiple Cultures
@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. ;)
Requesting Gravatar... The Other Steve Jun 15, 2007 6:48 AM
# re: Easily Test Your Code For Multiple Cultures
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. :-)
Requesting Gravatar... Jonathan de Halleux Jun 15, 2007 1:55 PM
# re: Easily Test Your Code For Multiple Cultures
I wrote that attribute a while ago :) If you look closely in MbUnit, you'll also see the PelikhanAttribute...
Requesting Gravatar... Christopher Steen Jun 18, 2007 9:10 PM
# Link Listing - June 18, 2007
Tip/Trick: Creating Packaged ASP.NET Setup Programs with VS 2005 [Via: ScottGu ] Calling an ASMX webservice...
Requesting Gravatar... Scott Jun 19, 2007 2:54 AM
# re: Easily Test Your Code For Multiple Cultures
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...
Requesting Gravatar... Robbie Jun 27, 2007 1:32 AM
# re: Easily Test Your Code For Multiple Cultures
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?

What do you have to say?

(will show your gravatar)
Please add 6 and 5 and type the answer here: