EasyMock - changing behavior for equals() and other Object methods
Question
The EasyMock documentation is pretty clear that
The behavior for the three object methods equals(), hashCode() and toString() cannot be changed for Mock Objects created with EasyMock, even if they are part of the interface for which the Mock Object is created.
The code that I'm trying to test uses equals() to compare my mock object to something else. I'd like to do something like
expect(mock.equals(obj)).andReturn(false);
When I do that, I get an IllegalStateException. No surprise there, given what the documentation says.
Does anyone have any suggestions for an alternate approach? Is there another way to control what the mock object will return when equals() is called on it? I suppose that I can create a subclass that overrides equals()
class FooImplOverrideEquals extends FooImpl {
public boolean equals;
public boolean equals(Object obj) { return equals; }
}
FooImplOverrideEquals mock = createMock(FooImplOverrideEquals.class);
mock.equals = false; // instead of expect(mock.equals(obj)).andReturn(false);
but this seems inelegant. I feel like I'm missing something important (like the reason why EasyMock doesn't let you override those object methods). Is there a better solution?
Solution
Many of the mocking libraries don't support this because it's generally a bad idea. If you're doing an equals() comparison then you have a value object, not a real collaborator and you're better off using a real instance. If you're using equals() to represent some other concept (isBestFriendsWith(other)), then you can stub that if appropriate.
OTHER TIPS
You cannot change the behaviour of equals, but you can use a Comparator to implement custom or partial comparisons.
Then you can use the comparator in EasyMock expectation using the method:
EasyMock.cmp
For instance, if you have a class Person with a name and an age instance variables, and you are interested only in comparing the name:
public class Person {
String name;
int age;
public boolean equals(Object obj) {
// the equals method compares the name and the age, but we are interested only in
// comparing the name
// other not-null checks...
Person other = (Person) obj;
if (this.age != other.age) {
return false;
}
if (other.name != null) {
return false;
}
return true;
}
}
public class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person person1, Person person2) {
//compare only the name
if (person1.getName().equals(person2.getName())) {
return 0;
}
return -1;
}
}
And use EasyMock.expect this way:
PersonComparator nameComparator = new PersonComparator();
Person person = new Person("Ana"); //the age doesn't matter
Person expectedPerson = EasyMock.cmp(comparisonPerson, nameComparator, LogicalOperator.EQUAL);
EasyMock.expect(personService.authenticate(expectedPerson)).andReturn(true);