2015-11-17 37 views
1

在.NET(VB或C#)和單元測試使用Microsoft.VisualStudio.TestTools.UnitTesting如何修改.NET中單個單元測試中的區域設置小數點分隔符?

如何有效地局部地改變一個單元測試中的區域設置小數分隔以便String.Format("{0:0.0}", aDouble)(其AFAIK是區域設置相關的)將產生串與修改區域設置?

編輯: 注意:我不問如何輸出文本與特定的語言環境。我在問如何在單元測試中更改區域設置的小數點分隔符以模擬具有不同小數點分隔符的系統中會發生什麼。 我不是從單元測試代碼中調用String.Format,而是從被測試的功能中調用String.Format。

其他信息:

我創造了一個VB .NET庫,我有一個類MyClassEncode(...)功能是寫作,除其他事項外,數字信息爲文本。

該組件將用於不同計算機可能具有「小數分隔符」(逗號或點)的不同配置的環境中。但是,我的組件應該對此不敏感,這意味着它應該始終輸出「point」(例如,在格式化數字時使用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 

CompareEncodedToTemplate功能將使用MyClass.Encode方法將信息寫入到MemoryStream那然後會相比,每行一個模板文本文件線,當他們不相等時,測試將失敗。

我想要「模擬」的是Encode函數在區域設置具有不同於「point」的小數點分隔符時的運行方式。顯然我的測試功能沒有按照我的預期工作:

我在計算機上運行測試,其中我設置了小數點分隔符,並且測試成功,所以我認爲「我的編碼函數會按我的意願工作,因爲測試通過「。

然後我在計算機上運行測試,並將小數點分隔符設置爲逗號,並且測試失敗。我意識到這是因爲在我的Encode邏輯中,我錯過了格式化雙精度時使用InvariantCulture。這意味着我的測試沒有像預期的那樣工作,因爲我應該能夠檢測到第一臺計算機的這種情況(因爲這是我想要創建測試的原因)。

預先感謝您。

+0

一個更多評論:我有單元測試和兩個不同的程序集中的測試功能,如果這可能會有所差異... – racucad

+0

我認爲'Encode_CultureWithCommaSeparator_OutputMatchesTemplate'的主要問題是您構建一個新的CultureInfo實例而不是像這樣從全局集合中訪問正確的文化信息:'System.Globalization.CultureInfo.GetCultureInfo(「es-ES」);' –

+0

好吧,我發現了這個問題,它與我如何設計測試有關類。我在實際改變文化之前實例化了MyClass,並簡化了我的解釋。我說「編碼」函數是用String寫的。格式,但實際上這些數字被轉換爲MyClass中的文本(這是故意的)。不幸的是,問題的本質並沒有在我的問題中得到體現,但我相信格倫費裏和喬納森狄金森是我寫這個問題的正確答案。 J.D的一個更「精心製作」,但G.F是讓我反應的人。 – racucad

回答

2

跑進正是這個問題,我的開發機器與我們的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())); 
+0

編輯:將結構調整到您的場景中,在那裏您想要檢查任何「ToString()」中的顯式文化或您擁有什麼。 –

0

據我所知,格式化字符串"{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 

參見標準數字格式字符串here的。然後基於單元測試範圍內的當前文化,它將相應地呈現字符串。

例如:

  • 1234.567( 「F」,EN-US) - > 1234.57
  • 1234.567( 「F」,DE-DE) - > 1234,57
  • 1234 ( 「F1」,EN-US) - > 1234.0
  • 1234( 「F1」,DE-DE) - > 1234,0

有ç上述鏈接中格式化數字的無數例子。我希望你覺得這有幫助。

+0

我可以確保在使用瑞典語作爲語言環境的系統中使用十進制逗號呈現String.Format(「{0:0.0}」,value)。 – racucad

+0

與String.Format(「{0.0}」,value)不同,否? –

+0

不好意思,無論多麼在意寫一篇文章......總會犯一個錯誤。我將在主要帖子中修復。謝謝。 – racucad

2

您應該考慮使用NumberFormatInfo這樣的:

var nfi = new System.Globalization.NumberFormatInfo(); 
nfi.NumberDecimalSeparator = ","; 
var formatted = (10.01).ToString("N", nfi); 

注:NumberFormatInfo具有與其他數字

從MSDN貨幣不同的設置:https://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo(v=vs.110).aspx

+0

謝謝,但我不問如何使用語言環境來格式化文本。我可以創建一個NumberFormatInfo,但我不會將它傳遞給Encode函數(這是編寫文本的函數)。我正在嘗試的是創建一個測試,以確保編碼函數獨立工作,以便系統配置語言環境。因此我需要在單元測試中模擬「區域小數點的更改」。 – racucad

+0

我會重新閱讀您的問題並回復 –

+0

這仍然是正確的答案。真正的問題是所描述的Encode()函數不是爲單元測試設計的。 –

0

這裏是有一個像你所描述的方法的類:

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

這兩個測試都能成功執行。

proof

爲您運行測試的操作前設置測試中的線程的區域性信息。

+0

你的「訣竅」很有幫助,因爲它讓我再次思考我是如何編寫測試的。謝謝。 – racucad

相關問題