C# 如何在.NET中的单个单元测试中修改区域设置小数分隔符?

C# 如何在.NET中的单个单元测试中修改区域设置小数分隔符?,c#,.net,vb.net,unit-testing,locale,C#,.net,Vb.net,Unit Testing,Locale,在.NET(VB或C#)中,使用Microsoft.VisualStudio.TestTools.UnitTesting进行单元测试: 如何有效地在单元测试中本地更改区域设置小数分隔符,以便String.Format(“{0:0.0}”,aDouble)(哪个AFAIK依赖于区域设置)将使用修改的区域设置生成字符串? 编辑: 注意:我不是在问如何输出具有特定区域设置的文本。我问的是如何在单元测试中更改locale的小数分隔符,以便模拟在具有不同小数分隔符的系统中会发生什么。 我不是从单元测试

在.NET(VB或C#)中,使用Microsoft.VisualStudio.TestTools.UnitTesting进行单元测试:

如何有效地在单元测试中本地更改区域设置小数分隔符,以便
String.Format(“{0:0.0}”,aDouble)
(哪个AFAIK依赖于区域设置)将使用修改的区域设置生成字符串?

编辑: 注意:我不是在问如何输出具有特定区域设置的文本。我问的是如何在单元测试中更改locale的小数分隔符,以便模拟在具有不同小数分隔符的系统中会发生什么。 我不是从单元测试代码中调用String.Format,而是从测试功能中调用String.Format

其他信息:

我正在用VB创建一个.NET库,我有一个类
MyClass
,它带有一个
Encode(…)
函数,该函数将数字信息作为文本写入

该组件将用于不同计算机可能对“小数分隔符”(逗号或点)具有不同配置的环境中。但是,我的组件应该对此不敏感,这意味着它应该始终输出“点”(例如,在格式化数字时使用
System.Globalization.CultureInfo.InvariantCulture

我想编写一个单元测试,以确保编码功能即使在系统区域设置十进制分隔符设置为“逗号”而不是“点”时也能继续工作。我做了一些研究,得出了如下结论:

Public Sub Encode_CultureWithCommaSeparator_OutputMatchesTemplate() ... Dim oldCulture = Threading.Thread.CurrentThread.CurrentCulture ' A culture that uses "," as decimal separator Threading.Thread.CurrentThread.CurrentCulture = New Globalization.CultureInfo("es-ES") CompareEncodedToTemplate(...) Threading.Thread.CurrentThread.CurrentCulture = oldCulture End Sub 公共子编码\u CultureWithCommaSeparator\u输出匹配模板() ... Dim oldCulture=Threading.Thread.CurrentThread.CurrentCulture “使用”“作为小数分隔符的区域性” Threading.Thread.CurrentThread.CurrentCulture=新全球化.CultureInfo(“es”) 比较编码模板(…) Threading.Thread.CurrentThread.CurrentCulture=oldCulture 端接头
CompareEncodedToTemplate
函数将使用
MyClass.Encode
方法将信息写入
MemoryStream
,然后将每行与模板文本文件行进行比较,当它们不相等时,测试将失败

我想“模拟”的是当区域设置的小数点分隔符不同于“点”时,
Encode
函数将如何运行。显然,我的测试功能没有如我预期的那样工作:

我在一台我设置了小数点分隔符的计算机上运行了测试,测试成功了,所以我想“我的编码功能可以正常工作,因为测试通过了”

然而,随后我在一台将十进制分隔符设置为逗号的计算机上运行了测试,测试失败。我意识到这是因为在我的
Encode
逻辑中,我在格式化double时没有使用
InvariantCulture
。这意味着,我的测试没有按预期工作,因为我应该能够在第一台计算机上检测到这种情况(因为这是我想要创建测试的原因)


提前谢谢。

据我所知,用
“{0.0}”
格式化字符串将始终显示为十进制

String.Format("{0:0}", 1.3); // Prints 1.3 regardless of culture
您必须更一般地指定它的名称,例如:

String.Format("{0:f}", 1.3); // Prints 1,3 if de-DE for example
请参见字符串的标准数字格式。然后基于单元测试范围上下文中的当前区域性,它将相应地呈现字符串

例如:

  • 1234.567(“F”,美国英语)->1234.57
  • 1234.567(“F”,de)->1234,57
  • 1234(“F1”,美国本土)->1234.0
  • 1234(“F1”,de)->1234,0

在前面提到的链接中,有无数格式化数字的例子。我希望你会发现这有帮助。

< P>你应该考虑使用<代码> NoMultFrastFiels<代码>:
var nfi = new System.Globalization.NumberFormatInfo();
nfi.NumberDecimalSeparator = ",";
var formatted = (10.01).ToString("N", nfi);
注意:
NumberFormatInfo
对货币和其他数字有单独的设置


从MSDN:

我的开发机器与我们的CI服务器正好遇到了这个问题。我编写了以下结构以提供帮助:

public struct CultureContext : IDisposable
{
    public static readonly CultureInfo CommaCulture = new CultureInfo("en-us")
    {
        NumberFormat =
        {
            CurrencyDecimalSeparator = ",",
            NumberDecimalSeparator = ",",
            PercentDecimalSeparator = ","
        }
    };

    public static readonly CultureInfo PointCulture = new CultureInfo("en-us")
    {
        NumberFormat =
        {
            CurrencyDecimalSeparator = ".",
            NumberDecimalSeparator = ".",
            PercentDecimalSeparator = "."
        }
    };

    private readonly CultureInfo _originalCulture;

    public CultureContext(CultureInfo culture)
    {
        _originalCulture = Thread.CurrentThread.CurrentCulture;
        Thread.CurrentThread.CurrentCulture = culture;
    }

    public void Dispose()
    {
        Thread.CurrentThread.CurrentCulture = _originalCulture;
    }

    public static void UnderBoth(Action test)
    {
        using (new CultureContext(PointCulture))
        {
            test();
        }

        using (new CultureContext(CommaCulture))
        {
            test();
        }
    }
}
然后可以对其进行如下测试:

CultureContext.UnderBoth(() => Assert.AreEqual("1.1", sut.ToString()));

下面是一个类,其方法与您描述的类似:

public class Class1
{
    public string FormatSpecial(double d) {
        return string.Format("{0:0.0}", d);
    }
}
以下是我的单元测试:

[TestClass]
public class UnitTest1
{
    Sample.Class1 instance;

    [TestInitialize]
    public void InitTests()
    {
        instance = new Sample.Class1();
    }

    [TestMethod]
    public void TestMethod1()
    {
        var result = instance.FormatSpecial(5.25);
        Assert.AreEqual("5.3", result);
    }

    [TestMethod]
    public void TestMethod2()
    {
        Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo("es-ES");
        var result = instance.FormatSpecial(5.25);
        Assert.AreEqual("5,3", result);
    }
}
这两个测试都成功执行


诀窍是在运行正在测试的操作之前,为测试中的线程设置区域性信息

我可以确保String.Format(“{0:0.0}”,value)在使用瑞典语作为语言环境的系统中使用十进制逗号呈现。这与String.Format(“{0.0}”,value)不同,不是吗?对不起,无论人们多么小心地写一篇文章。。。一个人总是犯错误。我会把它固定在主柱子上。谢谢,谢谢,但我不是在问如何使用区域设置格式化文本。我可以创建NumberFormatInfo,但我不会将其传递给Encode函数(即编写文本的函数)。我正在尝试的是创建一个测试,可以确保Encode函数将独立于系统如何配置语言环境工作。因此,我需要在单元测试中模拟“区域设置小数点的变化”,这仍然是正确的答案。真正的问题是所描述的Encode()函数不是为单元测试而设计的。很抱歉,但我不同意。建议的解决方案是,第一方面使编码函数输出“,”而不是小数点,这不是预期的行为。或者以某种方式建议将“NumberFormatInfo”传递给Encode函数。格伦·费里的另一个答案实际上是解决了真正的问题。与Jonathan Dickinson相同。编辑:根据您的场景调整结构,您希望在任何
ToString()
或您拥有的任何内容中检查显式区域性。还有一点注释:我在两个不同的程序集中进行了单元测试和测试功能,以防可能产生任何差异…我