Introduction
A few years ago, I came across with a treacherous bug in the COM interoperability for Microsoft Excel. To make it short, it happened that under globalization settings different than the US, some instructions were throwing the evil ComException
named "Old format or invalid type library". Microsoft suggested as a workaround to set the CultureInfo
to "en-US" immediately before the critical line(s) of code, taking care to restore the original CultureInfo
immediately after. That made things go smoothly, but soon I realized that the dirty trick could be easily hidden in a small class that would have the task to change the CultureInfo
in its constructor, having first buffered the original one in a member variable, for finally restoring it in the Dispose
method.
And here is the whole code for the SwitchCultureInfo
class:
using System;
using System.Globalization;
using System.Threading;
namespace Utilities
{
internal class SwitchCultureInfo: IDisposable
{
private readonly CultureInfo _original;
public SwitchCultureInfo(CultureInfo newCultureInfo)
{
_original = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = newCultureInfo;
}
public SwitchCultureInfo(string cultureName) :
this(new CultureInfo(cultureName))
{}
public void Dispose()
{
Thread.CurrentThread.CurrentCulture = _original;
}
}
}
Background
A few days ago, while writing Unit Tests for a globalized application, I realized that the old neat small class could have been useful for testing purposes. This is the scenario: there are a few extension methods that act as shortcuts for spitting out the week day names in the user's language, such as the following one:
public static string DayName(this DayOfWeek dayOfWeek)
{
return CultureInfo.CurrentCulture.DateTimeFormat.GetDayName(dayOfWeek);
}
Using the Code
While writing Unit Tests, it is fine to test such methods under different globalization settings, and here's how I ended writing them (using NUnit 2.5.10):
[Test]
public void DayName()
{
using (new SwitchCultureInfo("it-IT"))
Assert.AreEqual(DayOfWeek.Sunday.DayName(), "domenica");
using (new SwitchCultureInfo("en-US"))
Assert.AreEqual(DayOfWeek.Sunday.DayName(), "Sunday");
using (new SwitchCultureInfo("pl-PL"))
Assert.AreEqual(DayOfWeek.Tuesday.DayName(), "wtorek");
}
That initially looked fine, but I started thinking about the Fluent syntax that many frameworks are implementing (such as NUnit itself, but also NHibernate), and the using
instruction started to show the signs of its age. Why not implement some Fluent extension methods that could make the Unit Test more readable and amusing? And here's how I rewrote the Test method, now much more user-friendly:
using System;
using NUnit.Framework;
using Utilities;
using Program = System.Globalization.CultureInfo;
using Tests;
namespace Tests.Utilities
{
[TestFixture]
public class DayOfWeekExtensionFixture
{
[Test]
public void DayNameTest()
{
Now.WeAreTestingTheMethod(Utilities.DayOfWeekExtension.DayName);
When.The(Program.CurrentCulture)
.Is("Italian")
.And().TheCountryIs("Italy",
Assert.AreEqual, DayOfWeek.Sunday, "domenica");
When.The(Program.CurrentCulture)
.Is("Polish")
.And().TheCountryIs("Poland",
Assert.AreEqual, DayOfWeek.Tuesday, "wtorek");
When.The(Program.CurrentCulture)
.Is("English")
.And().TheCountryIs("United States",
Assert.AreEqual, DayOfWeek.Sunday, "Sunday");
}
}
}
Points of Interest
A reader has pointed out that it is "Nice, but not very practical". I always appreciate criticism, and I must admit that was really a good point. Moreover, in the same day I discovered that, one more time, I simply reinvented the wheel, since NUnit already has the SetCulture
attribute for switching to another culture, and that is the most concise way for accomplishing that task:
[Test, SetCulture("en-US")]
public void DayNameEn()
{
Assert.AreEqual("Sunday", DayOfWeek.Sunday.DayName());
}
[Test, SetCulture("it-IT")]
public void DayNameIt()
{
Assert.AreEqual("domenica", DayOfWeek.Sunday.DayName());
}
[Test, SetCulture("pl-PL")]
public void DayNamePl()
{
Assert.AreEqual("wtorek", DayOfWeek.Tuesday.DayName());
}
History
- 2011 July, 13 - First release.
- 2011 July, 15 - Improved the
When
and Now
classes.
- 2011 July, 20 - Added the NUnit example as a more concise way for checking the correct localization.