单元测试 - 实现等于仅便于测试

时间:2013-08-13 17:24:18

标签: java unit-testing junit equals

以下是我对单元测试的要求:

  1. 我想对我的制作类进行单元测试
  2. 我想将测试代码和生产代码分开,以便我只能发布生产代码
  3. 这似乎是合理的要求。但是,当我需要在对象上使用assertEquals等方法时,总会出现问题,因为这些方法要求覆盖equals方法。 equals方法必须在生产类中实现,但实际上仅用于测试。如果良好的编码实践规定如果equals被覆盖,则会变得更糟应该hashCode也应该实现,导致更多未使用的生产代码使生产类变得混乱。

    以下是User模型的简单示例(IntelliJ自动实现equalshashCode

    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;
        }
    }
    

    可以看出,equalshashCode会占用大量空间并使课堂变得杂乱无章。

    问题的一个解决方案可能是创建一个类UserTester,它可以使用assertUserEquals方法代替例如。 JUnit的assertEquals

    另一种解决方案可能是创建UserComparator。但是,JUnit似乎没有任何assertEquals需要Comparator

    关于这一点,最佳做法是什么?

3 个答案:

答案 0 :(得分:1)

Uniutils有一个完美的反射等于你可以用于单元测试的方法。通过这种方式,您的生产代码可以清楚地显示所有这些测试内容。

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; 
    } 
}

后来的测试:

User user1 = new User(1, "John", "Doe"); 
User user2 = new User(1, "John", "Doe"); 
assertReflectionEquals(user1, user2);

如果您正在使用Mockito,它有自己的方法来做同样的事情:

Mockito.verify(userDeleter).delete(Mockito.refEq(user));

答案 1 :(得分:0)

不是最有效但一种可能的方法是使用反射来比较字段。

public class Foo {

    int x;

    Foo(int in){
    x = in;
    }

    public static void main(String[] args) throws Exception{

        Foo o1 = new Foo(1),o2= new Foo(1);
        boolean allMatch = true;
        Class<?> c = Class.forName("Foo");
        Field[] fields =  c.getDeclaredFields();

        for(Field f: fields){
            allMatch &= f.get(o1)==f.get(o2);
        }
    }
}

答案 2 :(得分:0)

我看到两件不同的事情:

  1. 有时候不希望覆盖hashcode&amp; equals。它可能会改变您的计划行为,并可能会影响您的表现,请参阅Java Overriding hashCode() method has any Performance issue?

  2. 如果没有客户要求覆盖hashcode&amp; equals,就像它的值对象一样,你就不会这样做。您应该提供完全符合客户标准的代码,而不是更多。您的测试应该处理默认对象中的原始实现。

相关问题