使用反射从列表中获取对象

时间:2014-01-17 12:58:08

标签: java testing reflection comparison automated-tests

我正在编写一些webdriver测试,用于验证网页。页面主要包含Web表。我将测试数据存储在对象中,因此我将预期对象传递给测试并将其与网页中的实际对象进行比较。测试数据对象非常简单,大多只包含一串字符串:

public class PetOwnerDTO {
    private String ownerPhoneNr;
    private String ownerEmail;
    private String ownerAddress;
    // getters and setters skipped
}

既然有很多不同的对象需要验证,我正在尝试开发一个通用的对象比较器来为我做这件事。我已经拥有了:

package Helpers;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.List;

import static junit.framework.TestCase.fail;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalToIgnoringCase;

public class ObjectComparer {

    public static void compareObjects(Object obj1, Object obj2) {
        assertThat(obj1, is(notNullValue()));
        assertThat(obj2, is(notNullValue()));
        Class obj1Class = obj1.getClass();
        Class obj2Class = obj2.getClass();
        assertThat(obj1Class, is(sameInstance(obj2Class)));
        if (obj1Class.isArray()) {
            assertThat("Object2 is not an array", (obj2Class.isArray()));
            assertThat(Array.getLength(obj1), is(equalTo(Array.getLength(obj2))));
            for (int i = 0; i < Array.getLength(obj1); i++) {
                Object value1 = Array.get(obj1, i);
                Object value2 = Array.get(obj2, i);
                compareObjects(value1, value2);
            }
        }
        if (obj1 instanceof List<?>){
            throw new RuntimeException("Lists not supported, use looping");
        }
        Field[] fieldsObj1 = obj1Class.getDeclaredFields();
        Field[] fieldsObj2 = obj2Class.getDeclaredFields();
        assertThat(fieldsObj1.length, is(equalTo(fieldsObj2.length)));
        for (int i = 0; i < fieldsObj1.length; i++) {
            fieldsObj1[i].setAccessible(true);
            fieldsObj2[i].setAccessible(true);
            try {
                Object valueObj1 = fieldsObj1[i].get(obj1);
                Object valueObj2 = fieldsObj2[i].get(obj2);
                assertThat(valueObj1.toString(), is(equalToIgnoringCase(valueObj2.toString())));
            } catch (IllegalAccessException e) {
                fail("Unable to compare objects");
            }
        }
    }
}

问题在于第二个if:

if (obj1 instanceof List<?>){

如何从列表中获取对象?与Array.get()类似的东西? 或者有更好的方法吗?

2 个答案:

答案 0 :(得分:4)

看起来您正试图避免在每个测试对象中实现equals()。这让我印象深刻。有许多方法可以加快equals()方法的实施,包括:

  • 让您的IDE生成它。当然,Eclipse支持这个想法。

  • 依赖第三方库,例如Apache Commons Lang EqualsBuilder,它看起来很简单:

    @Override
    public boolean equals(Object obj) {
      return EqualsBuilder.reflectionEquals(this, obj);
    }
    

我强烈建议您采用这些方法中的一种,而不是构建一个基于反射的狡猾类,以逐个字段的方式测试相等性。拥有适当的平等方法有很多好处,包括:

  • 放入集合中时这些项目的正确行为。
  • 能够调用正常的JUnit断言(assertEquals()等。)

更改hashCode()时,不要忘记编写equals()方法。同样,有快捷方式(包括HashCodeBuilder)。

答案 1 :(得分:0)

您可以尝试使用Array() - List-API的方法。请注意,您必须使用相同数量的列表项才能正确比较它。