Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A CultureInfo switcher with Fluent syntax

0.00/5 (No votes)
20 Jul 2011 1  
For purposes of Unit Testing in globalized applications, you could sometimes need to change the CurrentCulture to test methods against different languages. Here are a few classes that provide a Fluent syntax for switching to another culture.

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here