Assume I want to unit test a method with this signature:
List<MyItem> getMyItems();
Assume MyItem
is a Pojo that has many properties, one of which is "name"
, accessed via getName()
.
All I care about verifying is that the List<MyItem>
, or any Iterable
, contains two MyItem
instances, whose "name"
properties have the values "foo"
and "bar"
. If any other properties don't match, I don't really care for the purposes of this test. If the names match, it's a successful test.
I would like it to be one-liner if possible. Here is some "pseudo-syntax" of the kind of thing I would like to do.
assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});
Would Hamcrest be good for this type of thing? If so, what exactly would be the hamcrest version of my pseudo-syntax above?
Thank you @Razvan who pointed me in the right direction. I was able to get it in one line and I successfully hunted down the imports for Hamcrest 1.3.
the imports:
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
the code:
assertThat( myClass.getMyItems(), contains(
hasProperty("name", is("foo")),
hasProperty("name", is("bar"))
));
Try:
assertThat(myClass.getMyItems(),
hasItem(hasProperty("YourProperty", is("YourValue"))));
Its not especially Hamcrest, but I think it worth to mention here. What I use quite often in Java8 is something like:
assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));
(Edited to Rodrigo Manyari's slight improvement. It's a little less verbose. See comments.)
It may be a little bit harder to read, but I like the type and refactoring safety. Its also cool for testing multiple bean properties in combination. e.g. with a java-like && expression in the filter lambda.
Assertj is good at this.
import static org.assertj.core.api.Assertions.assertThat;
assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");
Big plus for assertj compared to hamcrest is easy use of code completion.
AssertJ provides an excellent feature in extracting()
: you can pass Function
s to extract fields. It provides a check at compile time.
You could also assert the size first easily.
It would give :
import static org.assertj.core.api.Assertions;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName)
.containsExactlyInAnyOrder("foo", "bar");
containsExactlyInAnyOrder()
asserts that the list contains only these values whatever the order.
To assert that the list contains these values whatever the order but may also contain other values use contains()
:
.contains("foo", "bar");
As long as your List is a concrete class, you can simply call the contains() method as long as you have implemented your equals() method on MyItem.
// given
// some input ... you to complete
// when
List<MyItems> results = service.getMyItems();
// then
assertTrue(results.contains(new MyItem("foo")));
assertTrue(results.contains(new MyItem("bar")));
Assumes you have implemented a constructor that accepts the values you want to assert on. I realise this isn't on a single line, but it's useful to know which value is missing rather than checking both at once.
来源:https://stackoverflow.com/questions/12166415/how-do-i-assert-an-iterable-contains-elements-with-a-certain-property