我如何比较 BigDecimals 以使我的测试通过?
How can I compare BigDecimals to make my tests pass?
我在JUnit
测试中出现了以下同样的奇怪情况。
所以我有这个测试方法:
@Test
public void getNavInfoTest() throws ParseException {
TirAliquotaRamoI expectedObject = new TirAliquotaRamoI();
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date date;
date = formatter.parse("2015-08-01");
Date dataInizio = formatter.parse("2015-08-01");
Date dataFine = formatter.parse("2100-12-31");
expectedObject.setDataElaborazione(date);
expectedObject.setTassoLordoAnnuoAppl(BigDecimal.ZERO);
expectedObject.setTassoGiornalieroNetto(BigDecimal.ZERO);
expectedObject.setAliquota(BigDecimal.ONE);
expectedObject.setDataInizio(dataInizio);
expectedObject.setDataFine(dataFine);
TirAliquotaRamoI tirAliquotaRamoI = pucManager.getNavInfo(date);
assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());
}
最后,我只是简单地测试 tirAliquotaRamoI.getAliquota()
(从数据库查询中获得)是否具有为创建的 expectedObject
:
定义的相同字段的相同值
assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());
所以预期对象的字段是使用 BigDecimal.ONE
常量创建的,使用调试器我可以看到它的值为 1
.
而tirAliquotaRamoI.getAliquota()
得到的值为1.000000000
所以,理论上,两者都代表相同的值 1 但测试失败,我得到:
java.lang.AssertionError: expected:<1.000000000> but was:<1>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.fideuram.dbmanager.PucManagerTest.getNavInfoTest(PucManagerTest.java:90)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
为什么两者都代表相同的 1.0 值?我该如何解决这个问题才能通过测试?
试试这个:
assertEquals((int)tirAliquotaRamoI.getAliquota(), (int)expectedObject.getAliquota());
我认为 AssertEquals
只能比较同一类型的两个变量(int
到 int
,double
到 double
...)。在你的测试中,一个是小数,另一个不是,所以它可能无法比较它们。
tirAliquotaRamoI.getAliquota()
的数据类型是什么?是不是也是BigDecimal
因为BigDecimal.ONE
是BigDecimal
数据类型
如果tirAliquotaRamoI.getAliquota()是Long或Int或Float,你可以使用
assertEquals(tirAliquotaRamoI.getAliquota(), BigDecimal.ONE.intValue())
或
assertEquals(tirAliquotaRamoI.getAliquota(), BigDecimal.ONE.longValue())
虽然我不知道 JUnit 方法,但我猜问题与:
public boolean equals(Object x)
Compares this BigDecimal with the specified Object for equality.
Unlike compareTo, this method considers two BigDecimal objects equal
only if they are equal in value and scale (thus 2.0 is not equal to
2.00 when compared by this method).
可能,assertEquals()
正在使用上述方法,比较您的数字的 value 和 scale。
您可能想尝试使用 assertTrue() as suggested in
的方法
原因是 BigDecimal
equals
是如何实现的。 BigDecimal.ONE
构造为 new BigDecimal(BigInteger.ONE, 1, 0, 1)
。 equals 方法的实现方式如下(来自 JDK 源代码):
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflated().equals(xDec.inflated());
}
所以两个 BigDecimals
只有当它们具有相同的比例时才相等。 ONE
s 比例小于返回的 BigDecimal
,因此它们不相等。
我看到一些答案说你可以取 BigDecimal
的 floatValue。好吧,你不能。 BigDecimal
在处理更大的数字时使用,因此在这种特定情况下它会起作用,但这是一个糟糕的模式。
还好我们可以用compareTo
的方法!
assertTrue(tirAliquotaRamoI.getAliquota().compareTo(expectedObject.getAliquota()) == 0);
它并不完美,但会起作用!
在我看来他们有不同的 scales。
尝试 compareTo:
assertEquals(0, tirAliquotaRamoI.compareTo(expectedObject.getAliquota());
或者,如果您关心匹配比例,那么您必须使用 setScale(int newScale) 更改任一对象的比例以匹配另一个对象。
希望对您有所帮助。
感谢@David SN 指正
BigDecimal 比较也始终使用小数位数,因此您的测试失败了。
详情见Javadoc。
如果您只对值而不是比例感兴趣,那么在比较时考虑使用 stripTrailingZeros()。
assertEquals(
tirAliquotaRamoI.getAliquota().stripTrailingZeros(),
expectedObject.getAliquota().stripTrailingZeros()
);
我在JUnit
测试中出现了以下同样的奇怪情况。
所以我有这个测试方法:
@Test
public void getNavInfoTest() throws ParseException {
TirAliquotaRamoI expectedObject = new TirAliquotaRamoI();
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date date;
date = formatter.parse("2015-08-01");
Date dataInizio = formatter.parse("2015-08-01");
Date dataFine = formatter.parse("2100-12-31");
expectedObject.setDataElaborazione(date);
expectedObject.setTassoLordoAnnuoAppl(BigDecimal.ZERO);
expectedObject.setTassoGiornalieroNetto(BigDecimal.ZERO);
expectedObject.setAliquota(BigDecimal.ONE);
expectedObject.setDataInizio(dataInizio);
expectedObject.setDataFine(dataFine);
TirAliquotaRamoI tirAliquotaRamoI = pucManager.getNavInfo(date);
assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());
}
最后,我只是简单地测试 tirAliquotaRamoI.getAliquota()
(从数据库查询中获得)是否具有为创建的 expectedObject
:
assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());
所以预期对象的字段是使用 BigDecimal.ONE
常量创建的,使用调试器我可以看到它的值为 1
.
而tirAliquotaRamoI.getAliquota()
得到的值为1.000000000
所以,理论上,两者都代表相同的值 1 但测试失败,我得到:
java.lang.AssertionError: expected:<1.000000000> but was:<1>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.fideuram.dbmanager.PucManagerTest.getNavInfoTest(PucManagerTest.java:90)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
为什么两者都代表相同的 1.0 值?我该如何解决这个问题才能通过测试?
试试这个:
assertEquals((int)tirAliquotaRamoI.getAliquota(), (int)expectedObject.getAliquota());
我认为 AssertEquals
只能比较同一类型的两个变量(int
到 int
,double
到 double
...)。在你的测试中,一个是小数,另一个不是,所以它可能无法比较它们。
tirAliquotaRamoI.getAliquota()
的数据类型是什么?是不是也是BigDecimal
因为BigDecimal.ONE
是BigDecimal
数据类型
如果tirAliquotaRamoI.getAliquota()是Long或Int或Float,你可以使用
assertEquals(tirAliquotaRamoI.getAliquota(), BigDecimal.ONE.intValue())
或
assertEquals(tirAliquotaRamoI.getAliquota(), BigDecimal.ONE.longValue())
虽然我不知道 JUnit 方法,但我猜问题与:
public boolean equals(Object x)
Compares this BigDecimal with the specified Object for equality. Unlike compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by this method).
可能,assertEquals()
正在使用上述方法,比较您的数字的 value 和 scale。
您可能想尝试使用 assertTrue() as suggested in
原因是 BigDecimal
equals
是如何实现的。 BigDecimal.ONE
构造为 new BigDecimal(BigInteger.ONE, 1, 0, 1)
。 equals 方法的实现方式如下(来自 JDK 源代码):
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflated().equals(xDec.inflated());
}
所以两个 BigDecimals
只有当它们具有相同的比例时才相等。 ONE
s 比例小于返回的 BigDecimal
,因此它们不相等。
我看到一些答案说你可以取 BigDecimal
的 floatValue。好吧,你不能。 BigDecimal
在处理更大的数字时使用,因此在这种特定情况下它会起作用,但这是一个糟糕的模式。
还好我们可以用compareTo
的方法!
assertTrue(tirAliquotaRamoI.getAliquota().compareTo(expectedObject.getAliquota()) == 0);
它并不完美,但会起作用!
在我看来他们有不同的 scales。
尝试 compareTo:
assertEquals(0, tirAliquotaRamoI.compareTo(expectedObject.getAliquota());
或者,如果您关心匹配比例,那么您必须使用 setScale(int newScale) 更改任一对象的比例以匹配另一个对象。
希望对您有所帮助。
感谢@David SN 指正
BigDecimal 比较也始终使用小数位数,因此您的测试失败了。
详情见Javadoc。
如果您只对值而不是比例感兴趣,那么在比较时考虑使用 stripTrailingZeros()。
assertEquals(
tirAliquotaRamoI.getAliquota().stripTrailingZeros(),
expectedObject.getAliquota().stripTrailingZeros()
);