65.9K
CodeProject 正在变化。 阅读更多。
Home

具有流畅语法的 CultureInfo 切换器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.90/5 (4投票s)

2011年7月15日

CPOL

2分钟阅读

viewsIcon

23466

downloadIcon

215

为了在全局化应用程序中进行单元测试,有时您可能需要更改 CurrentCulture 以针对不同的语言测试方法。这里有一些类,它们提供了一种流畅的语法来切换到另一种区域性。

引言

几年前,我在 Microsoft Excel 的 COM 互操作性中遇到一个棘手的错误。 简而言之,在与美国不同的全球化设置下,某些指令会抛出名为“Old format or invalid type library”(旧格式或无效类型库)的邪恶 ComException。 Microsoft 建议的解决方法是在关键代码行之前立即将 CultureInfo 设置为“en-US”,并在之后小心地恢复原始 CultureInfo。 这使得事情顺利进行,但我很快意识到这个肮脏的技巧可以很容易地隐藏在一个小类中,该类将在其构造函数中更改 CultureInfo 的任务,首先将原始区域性缓冲到成员变量中,最后在 Dispose 方法中恢复它。

这是 SwitchCultureInfo 类的全部代码

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;
        }
    }
}

背景

几天前,在为全局化应用程序编写单元测试时,我意识到旧的整洁小类可能对测试目的有用。 这是场景:有一些扩展方法充当快捷方式,用于以用户的语言输出星期几的名称,例如以下方法

public static string DayName(this DayOfWeek dayOfWeek)
{
    return CultureInfo.CurrentCulture.DateTimeFormat.GetDayName(dayOfWeek);
}

Using the Code

在编写单元测试时,在不同的全球化设置下测试这些方法是很好的,以下是我编写它们的方式(使用 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");
}

最初看起来不错,但我开始思考许多框架正在实施的流畅语法(例如 NUnit 本身,还有 NHibernate),并且 using 指令开始显示出它的年龄迹象。 为什么不实现一些流畅的扩展方法,使单元测试更具可读性和趣味性呢? 以下是我重写测试方法的方式,现在更加用户友好

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");
        }
    }
}

关注点

一位读者指出它“不错,但不太实用”。 我总是欣赏批评,我必须承认那确实是一个很好的观点。 此外,在同一天,我发现我再次简单地重新发明了轮子,因为 NUnit 已经具有 SetCulture 属性,用于切换到另一种区域性,并且这是完成该任务的最简洁方法

[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());
}

历史

  • 2011 年 7 月 13 日 - 首次发布。
  • 2011 年 7 月 15 日 - 改进了 WhenNow 类。
  • 2011 年 7 月 20 日 - 添加了 NUnit 示例,作为检查正确本地化的更简洁方法。
© . All rights reserved.