10

単体テストの要件は次のとおりです。

  1. 本番クラスの単体テストをしたい
  2. 本番コードのみをリリースできるように、テスト コードと本番コードを分離したい

これは合理的な要件のようです。ただし、メソッドをオーバーライドassertEqualsする必要があるため、オブジェクトなどのメソッドを使用する必要がある場合は常に問題が発生します。equalsメソッドはequals本番クラスで実装する必要がありますが、実際にはテストにのみ使用されます。equalsifがオー​​バーライドされ、thenhashCodeも実装されるべきであるという適切なコーディング プラクティスが規定されている場合、これはさらに悪化し、未使用のプロダクション コードがさらに多くなり、プロダクション クラスが乱雑になります。

モデルを使用した簡単な例を次に示しUserます (IntelliJ 自動実装equalsおよび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;
    }
}

ご覧のとおり、多くのスペースを占有し、クラスを乱雑にしていますequalshashCode

この問題の解決策の 1 つは、クラスを作成することUserTesterですassertUserEquals。JUnit のassertEquals.

別の解決策は、UserComparator. ただし、JUnit にassertEqualsComparator.

この点でのベストプラクティスは何ですか?

4

3 に答える 3

1

Uniutilsには、単体テストに使用できる完全なリフレクション equals メソッドがあります。このようにして、本番コードはこのすべてのテストから明確に保たれます。

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));
于 2013-08-13T17:30:59.940 に答える
0

最も効率的ではありませんが、考えられる 1 つの方法は、リフレクションを使用してフィールドを比較することです。

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);
        }
    }
}
于 2013-08-13T17:31:43.597 に答える