2016-12-20 152 views
13

有沒有優雅的方式來斷言等號而忽略他們的類?我想在JUnit測試框架,使用它,但例如assert equals int long float

Assert.assertEquals(1,1L) 

失敗java.lang.AssertionError:期望值java.lang.Integer中< 1>卻被:java.lang.Long中< 1>

我希望有好的方法,其中地方僅比較值和使用int,長,浮動,字節,雙,BigDecimal的,BigInteger的,你的名字的作品...

+1

這是爲什麼downvoted?對我來說似乎是一個合法的問題。 – Mena

+1

我同意。有一個upvote!我也認爲答案不是微不足道的。 – Bathsheba

+0

我在考慮Number.toString.equals,但有科學的格式來處理 –

回答

8

一個解決辦法有一些開銷將包裹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比較。 對於構造函數long,構造函數的刻度設置爲默認值0,它通過構造函數中的一些計算推斷得到double。 因此,比較值(即在double值的邊緣情況下)可能的最安全方式是調用compareTo並且檢查結果是0

+1

我接受這個,因爲它是優雅的一線解決方案 –

+0

@PavelNiedoba歡呼。不過要注意頭頂上的開銷,你**是每次都在創建對象。 – Mena

+2

使用'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

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)); 

這樣,您就可以重用匹配,並斷言語句到底更具可讀性。

免責聲明:這只是僞代碼,並沒有經過測試,但應與一些調整工作。

但從Comparing Numbers in Java

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")); 
... 
3

根據我閱讀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將工作太。

+0

是的...修復它。 –

0

我認爲接受所有八種類型的數值(原始和對象),該方法必須採取字符串參數。呼叫者將要記住本成語的值轉換爲字符串:

""+value 

此外,如果該值不是整數(intIntegerlongLong),但浮點表示(floatdouble,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