Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing - implementing equals only to facilitate testing

Here are my requirements for unit testing:

  1. I would like to unit test my production classes
  2. 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?

like image 738
foens Avatar asked Aug 13 '13 17:08

foens


People also ask

What is unit testing implementation?

Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation. This testing methodology is done during the development process by the software developers and sometimes QA staff.

What is the purpose of unit testing?

Unit testing ensures that all code meets quality standards before it's deployed. This ensures a reliable engineering environment where quality is paramount. Over the course of the product development life cycle, unit testing saves time and money, and helps developers write better code, more efficiently.

Which of the following is correct about a unit test case?

Q 10 - Which of the following is correct about a Unit Test Case? A - A Unit Test Case is a part of code which ensures that the another part of code (method) works as expected.

Which of the following is true for unit testing?

Which of the following is true of unit tests? Unit tests are good for verifying that complicated user interaction behaves as expected. Unit tests are typically used to test small code modules rather than large sections of code. Unit tests are used to test the performance of a block of code.


1 Answers

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));
like image 55
Jk1 Avatar answered Sep 18 '22 05:09

Jk1