简体   繁体   English

奇怪的assertEquals等于并包含行为

[英]Weird assertEquals and contains behaviour

I have a very simple Pair class defined as follows: 我有一个非常简单的Pair类,定义如下:

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

I then have a Position class defined as follows: 然后,我将Position类定义如下:

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

}

That's all nice. 很好 However something peculiar happens when I try to test it. 但是,当我尝试对其进行测试时,会发生一些奇怪的事情。

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

}

The relevant output from the test is as follows: 测试的相关输出如下:

    [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

Having now posted all my relevant code and test results, my question is why would assertEquals(posOne, posThree) as well as calls to contains() fail? 现在已经发布了所有相关代码和测试结果,我的问题是为什么assertEquals(posOne,posThree)以及对contains()的调用会失败? As you can see at the top of the tests output, .equals() returns true. 如您在测试输出的顶部所见,.equals()返回true。 I'm so confused as to why these fail. 我很困惑为什么这些失败了。 Throughout my program I've had to use manual list traversal and manually calling equals() to check for list membership, but why ? 在整个程序中,我不得不使用手动列表遍历和手动调用equals()来检查列表成员身份,但是为什么呢? The documentation for List says List的文档说

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

And yet, .contains() fails. 但是, .contains()失败。 What the…? 什么...?

If you add an @Override annotation to the equals() method you'll see the problem. 如果在equals()方法中添加@Override批注,则会发现问题。 The parameter type must be Object , not Position . 参数类型必须是Object ,而不是Position

@Override
public boolean equals(Object other) {

Also, there's a typo in Pair.hashCode() . 另外, Pair.hashCode()有一个错字。

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

You want equals on Position and Pair to take an Object -- you're just overloading it with the declaration which takes a Pair. 您想让Position和Pair上的equals接受一个对象-您只是用接受Pair的声明来重载它。

Also your hashCode implementation on Pair is weird :) Maybe use the Apache EqualsBuilder and HashBuilder classes? 另外,您在Pair上的hashCode实现很奇怪:)也许使用Apache EqualsBuilder和HashBuilder类?

Relevant javadoc: http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object) 相关的Javadoc: http ://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#equals( java.lang.Object)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM