简体   繁体   English

如何反射性地比较各个领域的POJO

[英]How can I compare POJOs by their fields reflectively

I am basically looking for a unit testing framework, which I can use to compare POJOs which don't override equals and hascode methods. 我基本上是在寻找一个单元测试框架,我可以用它来比较不覆盖equals和hascode方法的POJO。 I had a look at JUnit, Test NG and Mockito but they don't seem to solve the purpose. 我看了一下JUnit,Test NG和Mockito,但他们似乎没有解决目的。

For example consider the code below : 例如,考虑以下代码:

public class CarBean { 

    private String brand;
    private String color;

    public CarBean (){
    }

    public CarBean (String brand, String color){
        this.brand= brand;
        this.color= color;
    }

    /**
     * @return the brand
     */
    public String getBrand() {
        return brand;
    }

    /**
     * @param the brand to set
     */
    public void setBrand(String brand) {
        this.brand= brand;
    }

    /**
     * @return the color
     */
    public String getColor() {
        return color;
    }

    /**
     * @param the color to set
     */
    public void setColor(String color) {
        this.color= color;
    }
}

The POJO CarBean represents a real world car. POJO CarBean代表了一辆真实世界的汽车。 It has two parameters, brand and color. 它有两个参数,品牌和颜色。 Now, suppose you have two car objects as below : 现在,假设您有两个汽车对象,如下所示:

CarBean car1 = new CarBean("Ford","Black");
CarBean car2 = new CarBean("Ford","Black");

Both the objects have same parameter values. 两个对象都具有相同的参数值。 But when you compare this using equals, it returns false : 但是当你使用equals比较它时,它返回false:

car1.equals(car2); // This returns false

Now I need to unit test a method that returns CarBean object. 现在我需要对返回CarBean对象的方法进行单元测试。 In this scenario I would either need to compare the carbean attributes one by one or I would need to implement equals() and hashcode() methods. 在这种情况下,我要么需要逐个比较carbean属性,要么我需要实现equals()和hashcode()方法。

So my question is - Is there already a unit testing framework which can handle this ? 所以我的问题是 - 是否已经有一个单元测试框架可以处理这个?

This type of reflection is built into Hamcrest as SamePropertyValuesAs , which compares bean-named properties (getFoo, isBar) instead of the fields that likely power them. 这种类型的反射作为SamePropertyValuesAs内置在Hamcrest中,它比较了bean命名的属性(getFoo,isBar),而不是可能为它们提供动力的字段。 Core Hamcrest support is built into JUnit, so you'd just need to add the Hamcrest library that includes the SamePropertyValuesAs matcher. 核心Hamcrest支持内置于JUnit中,因此您只需添加包含SamePropertyValuesAs匹配器的Hamcrest库。

assertThat(car1, samePropertyValuesAs(car2));

Unitils seems to do solve the purpose for me. Unitils似乎确实解决了我的目的。 The following APIs can compare objects reflectively. 以下API可以反射性地比较对象。 It can compare even if the attributes of a POJO themselves are user defined POJOs : 即使POJO本身的属性是用户定义的POJO,它也可以进行比较:

import static org.unitils.reflectionassert.ReflectionAssert.*;

// Exact field-by-field comparison
assertReflectionEquals(new Person("John", "Doe", new Address("New street", 5, "Brussels")), 
                                 new Person("John", "Doe", new Address("New street", 5, "Brussels"));

// Ignore Null / 0 values in the expected object
assertReflectionEquals(new Person("John", null, new Address("New street", 0, null)),
                                 new Person("John", "Doe", new Address("New street", 5, "Brussels"), 
                                 ReflectionComparatorMode.IGNORE_DEFAULTS); 

// Ignore collection order
assertReflectionEquals(Arrays.asList(new Person("John"), new Person("Jane")),
                                 new Person[] {new Person("Jane"), new Person("John")}, 
                                 ReflectionComparatorMode.LENIENT_ORDER);

// Ignore null/0 values + collection order
assertLenientEquals(Arrays.asList(new Person("John"), null),
                                 new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});

// Check only the firstName property 
assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"),
                                 new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});

Further information at Unitils Cookbook 有关Unitils Cookbook的更多信息

Override the toString() method in your pojo class like below 覆盖pojo类中的toString()方法,如下所示

@Override
public String toString() {
    return "brand: " + this.brand + ",color: " + this.color;
}


car1.toString().equals(car2.toString()); //It will return true if both objects has same values

In case you have large nos of parameter i will suggest you to go with bellow code 如果您有大量的参数,我建议您使用波纹管代码

public static boolean comparePOJO(Object obj1, Object obj2) {
    return new Gson().toJson(obj1).equals(new Gson().toJson(obj2));
}
comparePOJO(car1,car2); //It will return true

Since this would probably be implemented using reflection "reflection equals" is a reasonable search term, and indeed Google finds: 由于这可能是使用反射“反射等于”实现的,因此是一个合理的搜索词,Google确实发现:

http://www.unitils.org/tutorial-reflectionassert.html http://www.unitils.org/tutorial-reflectionassert.html

Nothing stops you from writing your own comparison 没有什么能阻止你写自己的比较

Using JUnit: 使用JUnit:

write a static method that takes 2 objects and does the assertions you want: 编写一个静态方法,它接受2个对象并执行您想要的断言:

public static void sameBrandAndColor(Car expected, Car actual){
     assertEquals(expected.getBrand(), actual.getBrand());
     assertEquals(expected.getColor(), actual.getColor());
}

Then in your tests just call your comparison method instead. 然后在您的测试中,只需调用您的比较方法。

@Test
public void test(){
    ...
    sameBrandAndColor(car1, car2);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从 Java 反射性地调用 Scala object 上的方法? - How can I reflectively call a method on a Scala object from Java? 如何从Java反射性地获取Scala对象上的字段? - How can I reflectively get a field on a Scala object from Java? Drools规则比较两个pojos的两个字段 - Drools rule to compare two fields of two pojos 我可以反射地实例化Java中的泛型类型吗? - can I reflectively instantiate a generic type in java? 如何反射性地打印方法主体? - How do I print the method body reflectively? 在Java9中,如果我不知道它的模块,我怎么能反思地加载一个类? - In Java9 how can I reflectively load a class if I don't know it's module? 我该如何在jUnit中实例化一个对象,该对象需要在其构造函数中反射地创建另一个对象? - How can I instantiate an object in jUnit, that needs to reflectively create another object inside its constructor? 在调用@Before setup()之后,如何反射地访问要运行的测试方法? - How can I reflectively access the test method to run after a call to @Before setup()? 我可以反射性地从 Java 调用一个 Kotlin 协程并将其包装在 CompletableFuture 中吗? - Can I invoke a Kotlin coroutine from Java reflectively and wrap it in CompletableFuture? 如何以 null 作为参数以反射方式调用方法? - How do I reflectively invoke a method with null as argument?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM