Creating tests for an assignment, I'm getting an strange AssertionError
exception.
I have changed it until i got to a simple case:
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;
}
Digging in both junit and hamcrest source code I have found that junit assertThat only calls matches on the matcher.
The matches method in this case is:
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);
}
}
Where arg should be "p2" and object should be "p1".
(It can be browsed at Hamcrest repository)
The results of the comparisons in areEqual method, using debugger inspection, are:
"p2 == null" false
"p1 != null" true
"p2.getClass().isArray()" false
"p2.equals(p1)" true
"equalTo(p1).matches(p2)" false
So as you can see, the code should reach the last else condition and return true
( p2.equals(p1)
), but equalTo(p1).matches(p2)
returns false
Thanks for your help
Why would you expect p2.equals(p1)
to return true
? You haven't overridden equals
in the Permutation
class, so it will use reference identity by default. You need to override equals
(and hashCode
, in general, to match equals) to indicate what you mean by equality when it comes to permutations.
EDIT: Now you've posted more code, it's clearer what's going on. Your equals method has this signature:
public boolean equals(Permutacion permutation){
That doesn't override Object.equals
, which is what the matcher will be using. Instead, it overloads it - introducing a new method, which is what is being called in the debugger inspection. If you write:
Object o1 = p1;
then p2.equals(o1)
will show false
in the debugger too - and that's effectively what the matcher is doing. Your equals method should look something like:
@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);
}
(You should also override hashCode
in a way which corresponds to this.)
Additionally:
elements
is null, or validate it in the constructor