5

I have a method that will return a list of objects of type MyClass. MyClass has many properties, but I care about type and count. I want to write a test that asserts that the returned list contains at least one element that matches a certain condition. For instance, I want at least one element in the list of type "Foo" and count 1.

I'm trying to figure out how to do this without literally looping over the returned list and checking each element individually, breaking if I find one that passes, like:

    boolean passes = false;
    for (MyClass obj:objects){
        if (obj.getName() == "Foo" && obj.getCount() == 1){
            passes = true;
        }
    }
    assertTrue(passes);

I really don't like this structure. I'm wondering if there's a better way to do it using assertThat and some Matcher.

ewok
  • 20,148
  • 51
  • 149
  • 254

3 Answers3

5

with hamcrest imports

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

you can test with

    assertThat(foos, hasItem(allOf(
        hasProperty("name", is("foo")),
        hasProperty("count", is(1))
    )));
logee
  • 5,017
  • 1
  • 26
  • 34
  • Will this assert that at least one item has both properties, or that there is at least one item that has each property? I.e. does this ensure it's the same item that has both? – ewok Oct 08 '18 at 03:04
  • 1
    Checks that there is AT LEAST 1 item in the list with name=="foo" AND that the same item has count==1 – logee Oct 08 '18 at 03:12
  • Looks like `org.hamcrest.Matchers` isn't found by my IDE. What's the maven repository I need for this? I figured it would be [this](https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all), but it's not – ewok Oct 08 '18 at 19:54
  • I am indeed using [v1.3](https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all/1.3) – logee Oct 08 '18 at 22:53
4
assertTrue(objects.stream().anyMatch(obj ->
    obj.getName() == "Foo" && obj.getCount() == 1
));

Or more likely:

assertTrue(objects.stream().anyMatch(obj ->
    obj.getName().equals("Foo") && obj.getCount() == 1
));
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
1

I don't know if it's worth using Hamcrest for this but it's good to know it's out there.

public class TestClass {
    String name;
    int count;

    public TestClass(String name, int count) {
        this.name = name;
        this.count = count;
    }

    public String getName() {
        return name;
    }

    public int getCount() {
        return count;
    }
}

@org.junit.Test
public void testApp() {
    List<TestClass> moo = new ArrayList<>();
    moo.add(new TestClass("test", 1));
    moo.add(new TestClass("test2", 2));

    MatcherAssert.assertThat(moo,
            Matchers.hasItem(Matchers.both(Matchers.<TestClass>hasProperty("name", Matchers.is("test")))
                    .and(Matchers.<TestClass>hasProperty("count", Matchers.is(1)))));
}
Charles
  • 944
  • 5
  • 9