2013-04-05 12 views
1

У меня есть очень простой класс пара определяется следующим образом:Weird assertEquals и содержит поведение

public class Pair<L, R> { 

    private L left; 
    private R right; 

    public Pair(L left, R right) { 
     this.left = left; 
     this.right = right; 
    } 

    public L getLeft() { 
     return this.left; 
    } 

    public R getRight() { 
     return this.right; 
    } 

    public String toString() { 
     return String.format("(%s, %s)", left, right); 
    } 

    public int hashCode() { 
     int hashFirst = left != null ? left.hashCode() : 0; 
     int hashSecond = left != null ? right.hashCode() : 0; 

     return (hashFirst + hashSecond) * hashSecond + hashFirst; 
    } 

    public Boolean equals(Pair other) { 
     if (other == null) { 
      return false; 
     } 

     return left.equals(other.getLeft()) && right.equals(other.getRight()); 
    } 
} 

Я тогда классовое положение определяется следующим образом:

public class Position { 

    private Pair<Integer, Integer> pair; 

    public Position(Integer x, Integer y) { 
     this.pair = new Pair<Integer, Integer>(x, y); 
    } 

    public Integer getX() { 
     return this.pair.getLeft(); 
    } 

    public Integer getY() { 
     return this.pair.getRight(); 
    } 

    public boolean equals(Position other) { 
     if (other == null) { 
      return false; 
     } 

     boolean b = getX() == other.getX() && getY() == other.getY(); 
     System.out.println(String.format("%s.equals(%s): %s", this, other, b)); 
     return b; 
    } 

    public int hashCode() { 
     return pair.hashCode(); 
    } 

    public String toString() { 
     return String.format("(%d, %d)", this.pair.getLeft(), 
           this.pair.getRight()); 
    } 

} 

Это все хорошо. Однако что-то особенное происходит, когда я пытаюсь его протестировать.

public class PositionTests extends TestCase { 

    private Position posOne; 
    private Position posTwo; 
    private Position posThree; 

    public PositionTests() { 
     posOne = new Position(7, 6); 
     posTwo = new Position(12, 7); 
     posThree = new Position(7, 6); 
    } 

    public void testCreationX() { 
     assertEquals(posOne.getX(), (Integer) 7); 
    } 

    public void testCreationY() { 
     assertEquals(posOne.getY(), (Integer) 6); 
    } 

    public void testEquality() { 
     // System.out.println("p1.e(p3): " + posOne.equals(posThree)); 
     // System.out.println("p3.e(p1): " + posThree.equals(posOne)); 
     //assertEquals(posOne, posThree); 
     assertEquals(posThree, posOne); 
    } 

    public void testInequality() { 
     assertFalse(posOne.equals(posTwo)); 
    } 

    public void testXEquality() { 
     assertEquals(posOne.getX(), posThree.getX()); 
    } 

    public void testYEquality() { 
     assertEquals(posOne.getY(), posThree.getY()); 
    } 

    public void testSymmTrue() { 
     assertTrue(posOne.equals(posThree) == posThree.equals(posOne)); 
    } 

    public void testSymmFalse() { 
     assertTrue(posOne.equals(posTwo) == posThree.equals(posTwo)); 
    } 

    public void testHashSetSame() { 
     Set<Position> hSet = new HashSet<Position>(); 
     hSet.add(posOne); 
     hSet.add(posThree); 
     hSet.add(posTwo); 
     hSet.add(posOne); 
     hSet.add(posOne); 
     hSet.add(posOne); 
     assertTrue(hSet.size() == 3); 
    } 

    public void testListContainsSuccess() { 
     List<Position> pList = new ArrayList<Position>(); 
     pList.add(posOne); 
     pList.add(posTwo); 
     assertTrue(pList.contains(posOne)); 
    } 

    public void testListContainsSuccessDiff() { 
     List<Position> pList = new ArrayList<Position>(); 
     pList.add(posOne); 
     pList.add(posTwo); 
     // System.out.println(pList); 
     // System.out.println(posThree); 
     Boolean b = pList.contains(posThree); 
     System.out.println("contains: " + b); 
     assertTrue(pList.contains(posThree)); 
    } 

    public void testListContainsFail() { 
     List<Position> pList = new ArrayList<Position>(); 
     pList.add(posOne); 
     pList.add(posThree); 
     assertFalse(pList.contains(posTwo)); 
    } 

} 

Соответствующий выход из теста выглядит следующим образом:

[junit] ------------- Standard Output --------------- 
    [junit] JUnit version is: 3.8.2 
    [junit] contains: false 
    [junit] (7, 6).equals((7, 6)): true 
    [junit] (7, 6).equals((7, 6)): true 
    [junit] (7, 6).equals((12, 7)): false 
    [junit] (7, 6).equals((12, 7)): false 
    [junit] (7, 6).equals((12, 7)): false 
    [junit] (7, 3).equals((7, 4)): false 
    [junit] ------------- ---------------- --------------- 
    [junit] 
    [junit] Testcase: testListContainsSuccessDiff took 0.005 sec 
    [junit]  FAILED 
    [junit] null 
    [junit] junit.framework.AssertionFailedError 
    [junit]  at com.group7.dragonwars.tests.PositionTests.testListContainsSuccessDiff(PositionTests.java:92) 
    [junit] 
    [junit] Testcase: testListContainsFail took 0 sec 
    [junit] Testcase: testYEquality took 0 sec 
    [junit] Testcase: testSymmTrue took 0.014 sec 
    [junit] Testcase: testSymmFalse took 0.001 sec 
    [junit] Testcase: testHashSetSame took 0 sec 
    [junit] Testcase: testListContainsSuccess took 0 sec 
    [junit] Testcase: testCreationY took 0 sec 
    [junit] Testcase: testEquality took 0.001 sec 
    [junit]  FAILED 
    [junit] expected:<(7, 6)> but was:<(7, 6)> 
    [junit] junit.framework.AssertionFailedError: expected:<(7, 6)> but was:<(7, 6)> 
    [junit]  at com.group7.dragonwars.tests.PositionTests.testEquality(PositionTests.java:43) 
    [junit] 
    [junit] Testcase: testInequality took 0.001 sec 
    [junit] Testcase: testXEquality took 0 sec 
    [junit] Testcase: testCreationX took 0 sec 
    [junit] Test com.group7.dragonwars.tests.AllTests FAILED 

После настоящего времени размещены все мои соответствующие коды и результаты тестов, мой вопрос, почему бы assertEquals (posOne, posThree), а также звонки to contains() не удается? Как вы можете видеть в верхней части вывода тестов, .equals() возвращает true. Я так смущен, почему они терпят неудачу. В течение всей моей программы мне приходилось использовать ручной просмотр списка и вручную называть equals() для проверки членства в списке, но почему? Документация для Списка говорит

Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)). 

И все же, .contains() не работает. Что за…?

ответ

2

Если вы добавите аннотацию @Override к методу equals(), вы увидите проблему. Тип параметра должен быть Object, а не Position.

@Override 
public boolean equals(Object other) { 

Кроме того, есть опечатка в Pair.hashCode().

int hashFirst = left != null ? left.hashCode() : 0; 
    int hashSecond = left != null ? right.hashCode() : 0; 
        ^^^^^ 
+0

Ого, я делал это неправильно всю свою жизнь. Большое спасибо. И да, честная ошибка в hashCode! Спасибо! –

0

Вы хотите равный на позиции и пару, чтобы принять объект - вы просто перегружать его с декларацией, которая принимает пару.

Также ваша реализация hashCode на Pair является странной :) Возможно, используйте классы Apache EqualsBuilder и HashBuilder?

Соответствующие Javadoc: http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object)