有沒有優雅的方式來斷言等號而忽略他們的類?我想在JUnit測試框架,使用它,但例如assert equals int long float
Assert.assertEquals(1,1L)
失敗java.lang.AssertionError:期望值java.lang.Integer中< 1>卻被:java.lang.Long中< 1>
我希望有好的方法,其中地方僅比較值和使用int,長,浮動,字節,雙,BigDecimal的,BigInteger的,你的名字的作品...
有沒有優雅的方式來斷言等號而忽略他們的類?我想在JUnit測試框架,使用它,但例如assert equals int long float
Assert.assertEquals(1,1L)
失敗java.lang.AssertionError:期望值java.lang.Integer中< 1>卻被:java.lang.Long中< 1>
我希望有好的方法,其中地方僅比較值和使用int,長,浮動,字節,雙,BigDecimal的,BigInteger的,你的名字的作品...
一個解決辦法有一些開銷將包裹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
比較。 對於構造函數long
,構造函數的刻度設置爲默認值0
,它通過構造函數中的一些計算推斷得到double
。 因此,比較值(即在double
值的邊緣情況下)可能的最安全方式是調用compareTo
並且檢查結果是0
。
我接受這個,因爲它是優雅的一線解決方案 –
@PavelNiedoba歡呼。不過要注意頭頂上的開銷,你**是每次都在創建對象。 – Mena
使用'equals'比較'BigDecimals'時必須謹慎:它與'compareTo'不一致,因爲它也需要考慮規模,[BigDecimal.equals的JavaDocs](http://docs.oracle.com/javase/ 8/docs/api/java/math/BigDecimal.html#equals-java.lang.Object-)另請參閱http://stackoverflow.com/q/6787142 – Hulk
將該功能包裝在您自己的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方法和基元比較雙重價值。如果使用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"));
...
根據我閱讀JLS的,過載分辨率
Assert.assertEquals(1,1L)
應該下定決心
Assert.assertEquals(long, long)
(根據記錄,assertEquals(long, long)
,assertEquals(float, float)
和assertEquals(double, double)
是適用通過嚴格調用,和第一個是最具體的;請參閱JLS 15.12.2.2。嚴格調用上下文允許原始加寬,但不是拳擊或拆箱。)
如果(因爲有證據表明)您的來電解析爲Assert.assertEquals(Object, Object)
,這意味着一個操作數必須已經是裝箱的類型。該超負荷的問題在於它使用equals(Object)
方法來比較對象,並且該方法的合同指定如果對象的相應類型不同,則結果爲false
。
如果這是你的真實代碼發生了什麼,那麼我懷疑使用is(T)
Matcher
的建議也可以。 is(T)
匹配器相當於is(equalTo(T))
,後者依賴於equals(Object)
...
有沒有現成的「不錯的方法」?
AFAIK,no。
我認爲真正的解決方案是更注意類型;例如
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(int, int)
Assert.assertEquals(i, (long) l); // OK - assertEquals(long, long)
編寫自定義Matcher
將工作太。
是的...修復它。 –
我認爲接受所有八種類型的數值(原始和對象),該方法必須採取字符串參數。呼叫者將要記住本成語的值轉換爲字符串:
""+value
此外,如果該值不是整數(int
,Integer
,long
,Long
),但浮點表示(float
, double
,Float
,Double
),該方法還必須採用參數epsilon
來容忍由於該表示而導致的不精確性。
因此,這裏是一個實現的想法(現在我不理楠的雙正,負零的情況 - 如果需要一個真正堅實地執行這些可以被添加)
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
這是爲什麼downvoted?對我來說似乎是一個合法的問題。 – Mena
我同意。有一個upvote!我也認爲答案不是微不足道的。 – Bathsheba
我在考慮Number.toString.equals,但有科學的格式來處理 –