是否有一种优雅的方式断言数字是平等的,而忽略了他们的类?我想在JUnit测试框架中使用它,例如
Assert.assertEquals(1,1L)
失败,出现java.lang.AssertionError:expected:java.lang.Integer< 1>但是:java.lang.Long< 1>
我希望有一个很好的方法可以只比较值并使用int,long,float,byte,double,BigDecimal,BigInteger,你可以命名...
答案 0 :(得分:12)
一个带有一些开销的解决方法是将值包装在BigDecimal个对象中,因为BigDecimal
构造函数重载需要long
,int
和double
个原语。
由于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语句最终会更具可读性。
免责声明:这只是伪代码,尚未经过测试,但应该进行一些调整。
答案 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
此外,如果值不是整数(int
,Integer
,long
,Long
),而是浮点表示(float
, double
,Float
,Double
),该方法还必须使用参数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