rishi
rishi

Reputation: 1842

Look for a property in List of object using Hamcrest matcher

I have a Java POJO.

public class Emp {    
    private String name;
    private int id;
}

I have a list of employees (target):

 List<Emp> target = new ArrayList<Emap>();
 // Add emp object in list
 assertThat(target, containsInAnyOrder(????));

In containsInAnyOrder, I have to use something like i.e. hasProperty("name" , is(equalTo("John")). I have to check for a specific property in the list for specific value so what should be the syntax. I did not find any example of "containsInAnyOrder" with List of objects.

Upvotes: 3

Views: 2050

Answers (2)

GhostCat
GhostCat

Reputation: 140417

I understand that you want a "generic" thing like: iterate a whole list; then retrieve a field of an object via name; to then check if any of the elements has a matching thing.

I think there is no such thing in Hamcrest: as that is ay too complicated for a pre-defined matcher.

In that sense, the only "answer" to exactly this requirement would be to create your own customer matcher that uses reflection to actually do that.

More details: you can start with an older answer of mine that contains a ready to use matcher that works for lists.

Actually, the only thing left to do now: change my list matcher to perform a different kind of check. And there you could make use of the Apache Commons EqualsBuilder listed in the other answer.

There should be no big hurdle in implementing that; its just "work".

But: I am not sure if that is really the correct approach. As said; the question you are trying to solve there sounds very specific too me; and you know: any unit test that uses reflection lacks the same problem that any "reflection based" code has - the compiler will not tell you, when somebody changes your production code; for example by changing the name of the field name.

Thus: instead of using reflection, I would rather compromise on the "production code" side of things; for example by adding a simple getter:

public class Emp {
... fields
  String getName() { return name; }

And instead of using reflection to compare generic properties, you write a matcher that knows to use that getter to fetch names and compare them.h

Upvotes: 1

Xinchao
Xinchao

Reputation: 3543

If your object-to-compare is always as simple as a Java Pojo, then maybe you can take a look of EqualsBuilder from Apache Commons Lang3. In particular, this method:

public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients)

You can implement your own "equals" matcher which delegates the comparison to reflectionEquals.

To do that, you subclass the TypeSafeDiagnosingMatcher<T> class from Hamcrest.

class ReflectiveEqualsMatcher<T> extends TypeSafeDiagnosingMatcher<T> {

    private final T other;

    public ReflectiveEqualsMatcher(T divisor) {
        this.other = divisor;
    }

    @Override
    protected boolean matchesSafely(T me, Description description) {
        return EqualsBuilder.reflectionEquals(me, other, true);
    }

    @Override
    public void describeTo(Description description) {
    }

    public static <T> ReflectiveEqualsMatcher<T> same(T other) {
        return new ReflectiveEqualsMatcher(other);
    }
}

To use it:

//static import ReflectiveEqualsMatcher.same first
assertThat(target, containsInAnyOrder(same(obj1), same(obj2), same(obj3)));

Upvotes: 1

Related Questions