1

I have an English setup laptop and my colleauge has a German one. I have a unit test as below:

  @Test
  public void myTest() {
    String randomValue = roundFloat(4, 0.32258437873357226);
    Assert.assertEquals(Double.parseDouble(randomValue), 0.3225);
  }

  public String roundFloat(int decimalDigits, Number randomValue) {

    String formatPattern = getFormatPattern(decimalDigits);
    DecimalFormat decimalFormat = new DecimalFormat(formatPattern);
    decimalFormat.setRoundingMode(RoundingMode.FLOOR);
    return decimalFormat.format(randomValue);
  }

The default decimal delimiter in English is . and in German it is ,. Therefore, the test works well on my machine but when my colleauge runs it, it complains with:

java.lang.NumberFormatException: For input string: "0,3225"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
    at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.lang.Double.parseDouble(Double.java:538)
    at de.vwag.fda.common.MeteringUnitTest.roundFloatTest(MeteringUnitTest.java:174)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:133)
    at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:598)
    at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173)
    at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
    at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:824)
    at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.testng.TestRunner.privateRun(TestRunner.java:794)
    at org.testng.TestRunner.run(TestRunner.java:596)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:377)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:371)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:332)
    at org.testng.SuiteRunner.run(SuiteRunner.java:276)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1212)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1134)
    at org.testng.TestNG.runSuites(TestNG.java:1063)
    at org.testng.TestNG.run(TestNG.java:1031)
    at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:135)
    at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:193)
    at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:94)
    at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:146)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:377)
    at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:138)
    at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:465)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:451)

So, how can i modify my test, so that, it gets run for all the possible local setups ?

Jeff
  • 7,767
  • 28
  • 85
  • 138
  • A possible solution to your problem could be found here : https://stackoverflow.com/questions/8190124/junit-testing-double-tostring-in-multiple-cultures – Kevin Addison Jun 21 '21 at 13:28

2 Answers2

0

From the DecimalFormat documentation:

To obtain a NumberFormat for a specific locale, including the default locale, call one of NumberFormat's factory methods, such as getInstance(). In general, do not call the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat.

This means that you can use this to get a number formatter with a custom locale, and set the rounding mode like you did in your code:

NumberFormat format = NumberFormat.getNumberInstance(Locale.GERMAN);
if(format instanceof DecimalFormat) {
    ((DecimalFormat) format).setRoundingMode(RoundingMode.FLOOR);
}
Pieter12345
  • 1,713
  • 1
  • 11
  • 18
0

I would just use System.printf with the proper locale.

System.out.printf(Locale.GERMAN, "%.3f%n", 123.723);
System.out.printf(Locale.ENGLISH, "%.3f%n", 123.723);

Prints

123,723
123.723

But the formatters also accept a Locale. So if you wanted to do currency you could call:

NumberFormat df = NumberFormat.getCurrencyInstance(Locale.ENGLISH);

You can round to a specify number of digits as follows.

String randomValue = roundFloat(4, .32258437873357226, Locale.GERMAN);
System.out.println(randomValue);
randomValue = roundFloat(7,.32258437873357226, Locale.ENGLISH);
System.out.println(randomValue);

prints

0,3225
0.3225843

roundFloat method

public static String roundFloat(int decimalDigits, Double randomValue, Locale locale) {
    DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(locale);
    df.setMaximumFractionDigits(decimalDigits);
    df.setRoundingMode(RoundingMode.FLOOR);
   return df.format(randomValue);
}
WJS
  • 36,363
  • 4
  • 24
  • 39
  • How can i re-write the `roundFloat` method using the `NumberFormat` ? The `decimalDigits` is the number of the digits which must exist after rounding, however i don't know, how can i do it using `NumberFormat`. – Jeff Jun 22 '21 at 06:35
  • Check out my updated answer. Perhaps it can help. – WJS Jun 22 '21 at 13:53