断言等于int long float

时间:2016-12-20 12:14:22

标签: java junit

是否有一种优雅的方式断言数字是平等的,而忽略了他们的类?我想在JUnit测试框架中使用它,例如

Assert.assertEquals(1,1L)

失败,出现java.lang.AssertionError:expected:java.lang.Integer< 1>但是:java.lang.Long< 1>

我希望有一个很好的方法可以只比较值并使用int,long,float,byte,double,BigDecimal,BigInteger,你可以命名...

5 个答案:

答案 0 :(得分:12)

一个带有一些开销的解决方法是将值包装在BigDecimal个对象中,因为BigDecimal构造函数重载需要longintdouble个原语。

由于new BigDecimal(1l).equals(new BigDecimal(1.0))持有true

Assert.assertEquals(new BigDecimal(1.0), new BigDecimal(1l));  

应该适合你。

修改

如下Hulk所示,BigDecimal对象的比例用于equals比较,但不用于compareTo比较。 虽然对于构造函数0,缩放设置为默认long,但是通过构造函数中的double计算得出。 因此,比较值的最安全方法(即在double值的边缘情况下)可能通过调用compareTo并检查结果是0

答案 1 :(得分:6)

根据我对JLS的解读,

的重载决议
Assert.assertEquals(1,1L)

应解析为

Assert.assertEquals(long, long)

(对于记录,assertEquals(long, long)assertEquals(float, float)assertEquals(double, double) 适用于严格调用,第一个是最具体的;请参阅{{ 3}}。严格的调用上下文允许原始扩展,但不能装箱或拆箱。)

如果(证据表明)您的呼叫正在解析为Assert.assertEquals(Object, Object),则意味着其中一个操作数必须已经为盒装类型。该重载的问题在于它使用equals(Object)方法来比较对象,并且该方法的合同指定,如果对象'},则结果为false。各自的类型不同。

如果您的真实代码中发生了这种情况,那么我怀疑使用is(T) Matcher的建议是否有效。 is(T)匹配器相当于is(equalTo(T)),后者依赖于equals(Object) ......

是否存在"漂亮的方法"?

AFAIK,没有。

我认为真正的解决方案是对类型更加关注;例如

 int i = 1;
 Long l = 1L;
 Assert.assertEquals(i, l);         // Fails
 Assert.assertEquals((long) i, l);  // OK - assertEquals(Object, Object)
 Assert.assertEquals((Long) i, l);  // OK - assertEquals(Object, Object)
 Assert.assertEquals(i, (int) l);   // OK - assertEquals(long, long) 
                                    //      it would bind to an (int, int) 
                                    //      overload ... it it existed.   
 Assert.assertEquals(i, (long) l);  // OK - assertEquals(long, long)

编写自定义Matcher也可以。

答案 2 :(得分:4)

在您自己的Matcher中包含该功能,并将其与assertThat一起使用。

样本匹配器:

class IsAnyNumber extends BaseMatcher {
  final Object expected;
  //...
  public boolean matches(Object actual) {
    // compare / transform / check type / ensure: String, double, int, long
    // example via BigDecimal as seen from Mena (without checks)
    return new BigDecimal(expected).equals(new BigDecimal(actual));
  }
  // ...
}

// somewhere else:
public static IsAnyNumber is(Object expected) {
  return new IsAnyNumber(expected);
}

在测试中,然后调用静态方法:

assertThat(1, is(1L));
assertThat(1, is(1.0));
assertThat(1L, is(1));

这样你可以重用你的匹配器,并且assert语句最终会更具可读性。

免责声明:这只是伪代码,尚未经过测试,但应该进行一些调整。

但请注意Comparing Numbers in Java

答案 3 :(得分:1)

创建自己的断言方法并比较基元的double值。如果使用BigDecimal,则必须将原始值转换为BigDecimal

static void assertEquals(Number number1, Number number2) {
  Assert.assertEquals(number1.doubleValue(), number2.doubleValue());
}

static void assertEquals(BigDecimal number1, BigDecimal number2) {
  if (number2.compareTo(number1) != 0) {
    Assert.fail("Values are not equal. ..... ");
  }
}

static void assertEquals(Number number1, BigDecimal number2) {
  assertEquals(new BigDecimal(number1.doubleValue()), number2);
}

static void assertEquals(BigDecimal number1, Number number2) {
  assertEquals(number2, number1);
}

可以这样使用:

assertEquals(1, new BigDecimal("1.0"));
assertEquals(1.0d, 1);
assertEquals(new Float(1.0f), 1.0d);
assertEquals(new BigDecimal("1.00000"), new BigDecimal("1.0"));
...

答案 4 :(得分:0)

我认为接受所有八种类型的数值(原始和对象),该方法必须采用字符串参数。调用者必须记住通过这个习语将值转换为字符串:

""+value

此外,如果值不是整数(intIntegerlongLong),而是浮点表示(floatdoubleFloatDouble),该方法还必须使用参数epsilon来容忍由于表示而导致的不精确。

所以这是一个实现的想法(现在我忽略了NaN的情况以及double的正负零 - 如果需要真正可靠的实现,可以添加这些)

private static boolean equalsNumerically(String n1String
                                        , String n2String
                                        , double epsilon) {
    try {
        Long n1Long = new Long(n1String);
        Long n2Long = new Long(n2String);
        return n1Long.equals(n2Long);
    } catch (NumberFormatException e) {
        /*
         * If either one of the number is not an integer, try comparing
         * the two as Double
         */
        try {
            Double n1Double = new Double(n1String);
            Double n2Double = new Double(n2String);
            double delta = ( n1Double - n2Double) / n2Double;
            if (delta<epsilon) {
                return true;
            } else {
                return false;
            }
        } catch (NumberFormatException e2) {
            return false;
        }
    } 
}

测试代码

    int     primitiveInt = 1;
    long    primitiveLong = 1L;
    float   primitiveFloat = 0.999999F;
    double  primitiveDouble = 0.999999D;
    Integer objectInt = new Integer(1);
    Long    objectLong = new Long(1);
    Float   objectFloat = new Float(0.999999);
    Double  objectDouble = new Double(0.999999);

    final double epsilon = 1E-3;

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, 0)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveLong, 0): %s %s %s%n"
            , primitiveInt, primitiveLong, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, epsilon));
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveLong, epsilon)): %s %s %s%n"
            , primitiveInt, primitiveLong, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveFloat, epsilon)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveFloat, 0): %s %s %s%n"
            , primitiveInt, primitiveFloat, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveDouble, epsilon)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveDouble, epsilon): %s %s %s%n"
            , primitiveInt, primitiveDouble, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectInt, 0)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+objectInt, 0): %s %s %s%n"
            , primitiveInt, objectInt, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectLong, 0)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+objectLong"
            + ", \"\"+objectLong, 0): %s %s %s%n"
            , primitiveInt, primitiveLong, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectFloat, epsilon));
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+objectFloat, epsilon)): %s %s %s%n"
            , primitiveInt, objectFloat, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectDouble, epsilon)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+objectDouble, 0): %s %s %s%n"
            , primitiveInt, objectDouble, epsilon);

测试输出

Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, 0): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, epsilon)): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveFloat, 0): 1 0.999999 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveDouble, epsilon): 1 0.999999 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectInt, 0): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectLong, 0): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectFloat, epsilon)): 1 0.999999 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectDouble, 0): 1 0.999999 0.001