Unit testing - implementing equals only to facilitate testing
equals, java, junit, unit-testing
Solution
Uniutils has a perfect reflection equals method you can use for unit testing. This way your production code remains clear from all this test stuff.
public class User {
private long id;
private String first;
private String last;
public User(long id, String first, String last) {
this.id = id;
this.first = first;
this.last = last;
}
}
Later in test:
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);
If you're using Mockito it has it's own means to do the same thing:
Mockito.verify(userDeleter).delete(Mockito.refEq(user));
Problem
Here are my requirements for unit testing: - I would like to unit test my production classes - I would like to separate test code and production code apart such that I can release production code only This seems like reasonable requirements. However, a problem always arises when I need to use methods such as `assertEquals` on objects as these requires that the `equals` method is overridden. The `equals` method would have to be implemented in production classes but is actually only used for testing. This becomes even worse when good coding practices dictates that if `equals` is overridden, then should `hashCode` also be implemented resulting in even more unused production code that clutters the production classes. Here is a simple example with a `User` model (IntelliJ autoimplemented `equals` and `hashCode`) ``` public class User { public long id; public long companyId; public String name; public String email; public long version; @Override public boolean equals(Object o) { if(this == o) return true; if(o == null || getClass() != o.getClass()) return false; User user = (User) o; if(companyId != user.companyId) return false; if(id != user.id) return false; if(version != user.version) return false; if(!email.equals(user.email)) return false; if(!name.equals(user.name)) return false; return true; } @Override public int hashCode() { int result = (int) (id ^ (id >>> 32)); result = 31 * result + (int) (companyId ^ (companyId >>> 32)); result = 31 * result + name.hashCode(); result = 31 * result + email.hashCode(); result = 31 * result + (int) (version ^ (version >>> 32)); return result; } } ``` As it can be seen, `equals` and `hashCode` takes up a lot of space and clutters the class. One solution to the problem could be to create a class, `UserTester`, which could have an `assertUserEquals` method that could be used instead of eg. JUnit's `assertEquals`. Another solution could be to create a `UserComparator`. However, it does not seem like JUnit have any `assertEquals` that takes a `Comparator`. What is best practices on this point?