本文介绍了如何比较BigDecimals以使测试通过?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在进行JUnit测试时遇到以下相同的奇怪情况.

I have the following same strange situation into a JUnit test.

所以我有这个测试方法:

So I have this test method:

@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定义的相同字段相同的值:

At the end I am simply testing if the tirAliquotaRamoI.getAliquota() (obtained from a DB query) have the same value of the same field defined for the created expectedObject:

assertEquals(tirAliquotaRamoI.getAliquota(), expectedObject.getAliquota());

因此,使用BigDecimal.ONE constand并使用调试器创建了预期对象的字段,我看到它的值是1.

So the field for the expected object is created using the BigDecimal.ONE constand and using the debugger I can see that its value is 1.

tirAliquotaRamoI.getAliquota()获得的值为1.000000000

因此,理论上,两者都表示相同的值1,但测试失败,我得到:

So, in theory, both represent the same value 1 but the test fail and I obtain:

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$1.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$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.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)

为什么两个都代表ame 1.0值?如何解决此问题以通过测试?

Why if both represent the ame 1.0 value? How can I fix this issue to pass the test?

推荐答案

原因是BigDecimal equals的实现方式. BigDecimal.ONE被构造为new BigDecimal(BigInteger.ONE, 1, 0, 1). equals方法以以下方式实现(来自JDK源代码):

The reason is how the BigDecimal equals is implemented. BigDecimal.ONE is constructed as new BigDecimal(BigInteger.ONE, 1, 0, 1). The equals method is implemented in the following way (from JDK source code):

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的标度小于返回的BigDecimal的标度,因此它们不相等.

So two BigDecimals are equal only if they have the same scale. ONEs scale is smaller than returned BigDecimal's so they're not equal.

我看到一些回答,说您可以使用 fc的 floatValue .好吧,你不能. BigDecimal用于处理较大的数字,因此在某些情况下它可以工作,但这是一个错误的模式.

I saw some answers saying that you can take floatValue of BigDecimal. Well, you can't. BigDecimal is used when dealing with bigger numbers so in this certain case it would work, but is a bad pattern.

但是幸运的是我们可以使用compareTo方法!

But fortunately we can use compareTo method!

assertTrue(tirAliquotaRamoI.getAliquota().compareTo(expectedObject.getAliquota()) == 0);

这不是完美的,但可以使用!

It's not perfect but will work!

这篇关于如何比较BigDecimals以使测试通过?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 02:52