为什么这个断言断言会抛出AssertionError?

时间:2011-12-12 05:54:51

标签: java junit hamcrest

为作业创建测试,我得到一个奇怪的AssertionError例外。

我改变它直到我得到一个简单的案例:

List<Integer> elements= new ArrayList<Integer>();
elements.add(1);
elements.add(2);
elements.add(3);

Permutation p2 = new Permutation(elements);
Permutation p1 = new Permutation(elements);

assertThat(p2, equalTo(p1));

Permutation.java:

public class Permutation {

  private List<Integer> elements;

  public Permutation(List<Integer> elements) {
    this.elements = elements;
  }

public boolean equals(Permutacion permutation){
  if ( this.elements.size() != permutation.elements.size()){
    return false;
  }

  Iterator<Integer> iterThis = this.elements.iterator();
  Iterator<Integer> iterOther = permutation.elements.iterator();
  while ( iterThis.hasNext() && iterOther.hasNext()){
    if ( iterThis.next() != iterOther.next()){
      return false;
    }
  }

  return true;

}

挖掘junit和hamcrest源代码我发现junit assert只能在匹配器上调用匹配。

这种情况下的匹配方法是:

public boolean matches(Object arg) {
    return areEqual(arg, object);
}

private static boolean areEqual(Object o1, Object o2) {
    if (o1 == null) {
        return o2 == null;
    } else if (o2 != null && isArray(o1)) {
        return isArray(o2) && areArraysEqual(o1, o2);
    } else {
        return o1.equals(o2);
    }
}

其中arg应为“p2”,对象应为“p1”。

(可在Hamcrest repository浏览

使用调试器检查的areEqual方法中的比较结果是:

"p2 == null"                    false   
"p1 != null"                    true    
"p2.getClass().isArray()"       false   
"p2.equals(p1)"                 true    
"equalTo(p1).matches(p2)"       false   

正如您所看到的,代码应该达到最后一个条件并返回truep2.equals(p1)),但equalTo(p1).matches(p2)会返回false

感谢您的帮助

1 个答案:

答案 0 :(得分:7)

为什么您希望p2.equals(p1)返回true?您尚未在equals类中重写Permutation,因此默认情况下它将使用引用标识。您需要覆盖equals(和hashCode,一般来说,匹配等于)以表明在排列方面您的平等意味着什么。

编辑:现在你发布了更多的代码,它更清楚发生了什么。你的equals方法有这个签名:

public boolean equals(Permutacion permutation){

覆盖Object.equals,这就是匹配器将使用的内容。相反,它重载它 - 引入一个新方法,这是在调试器检查中调用的方法。如果你写:

Object o1 = p1;

然后p2.equals(o1)也会在调试器中显示false - 这实际上是匹配器正在做的事情。您的equals方法应该类似于:

@Override
public boolean equals(Object other)
{
    if (other == null || other.getClass() != this.getClass())
    {
        return false;
    }
    Permutation otherPermutation = (Permutation) other;

    // List.equals should do the right thing here
    return elements.equals(otherPermutation.elements);
}

(您还应该以与此相对应的方式覆盖hashCode。)

此外:

  • 要么考虑elements为空的情况,要么在构造函数
  • 中验证它
  • 平等在最终类中最容易定义
  • 由于你没有制作清单的防御性副本,所以在建设之后它可能会被调用者变异;例如,如果您将排列用作地图中的关键字,则可能会导致问题。