I wrote the following extension method:
public static class DecimalExtensions
{
public static string FormatCurrency(this decimal instance)
{
return string.Format("{0:c}", instance);
}
}
The NUnit test:
[TestFixture]
public class DecimalExtensionsTests
{
[Test]
public void Format_should_return_formatted_decimal_string()
{
// Arrange
decimal amount = 1000;
// Act
string actual = amount.FormatCurrency();
// Assert
Assert.AreEqual("R 1 000,00", actual);
}
}
My test is failing and I am not sure why. The error that I get is the following:
String lengths are both 10. Strings differ at index 3.
Expected: "R 1 000,00"
But was: "R 1 000,00"
--------------^
Your problem indeed comes from different space representation in numeric format. Space you're having troubles with is defined in NumberFormatInfo
class' CurrencyGroupSeparator
property. If you check character codes of both standard ASCII space and currency group separator space with the following snippet
Console.WriteLine("Space code: {0}", (Int32)' ');
var separator = Thread.CurrentThread.CurrentCulture.NumberFormat
.CurrencyGroupSeparator;
Console.WriteLine("Currency separator code: {0}", (Int32)separator[0]);
... you'll find that it prints 32
and 160
respectively. This is why your string comparison fails.
For the purpose of unit testing, you can set the separator to actual ASCII space, like this:
Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyGroupSeparator = " ";
However, I would advise against it. You need to consider what happens when developer with other culture settings will run your unit test. Most likely it will fail, as resulting strings might differ. To make your method more usable (and unit tests more isolated), simply add overload that accepts culture info:
public static string FormatCurrency(this decimal instance)
{
return instance.FormatCurrency(Thread.CurrentThread.CultureInfo);
}
public static string FormatCurrency(this decimal instance, CultureInfo culture)
{
return string.Format(culture, "{0:c}", instance);
}
In your unit test, you write test against second method, with some well-known and easy to verify culture settings (might even fix the space to make it easier):
[Test]
public void FormatCurrency_should_return_formatted_decimal_string()
{
decimal amount = 1000;
var culture = CultureInfo.CreateSpecificCulture("en-us");
// replacing space (160) with space (32)
culture.NumberFormat.CurrencyGroupSeparator = " ";
// Act
string actual = amount.FormatCurrency(culture);
// Assert
Assert.AreEqual("$1 000.00", actual);
}
And in your real application you simply use culture-less overload and let the culture be the one from user's current settings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With