具有流畅语法的 CultureInfo 切换器






3.90/5 (4投票s)
为了在全局化应用程序中进行单元测试,有时您可能需要更改 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 日 - 改进了
When
和Now
类。 - 2011 年 7 月 20 日 - 添加了 NUnit 示例,作为检查正确本地化的更简洁方法。