Как утверждать, что Iterable содержит элементы с определенным свойством?
Предположим, что я хочу unit test метод с этой сигнатурой:
List<MyItem> getMyItems();
Предположим, что MyItem
- это Pojo, обладающее многими свойствами, один из которых "name"
, доступ через getName()
.
Все, что мне нужно для проверки, состоит в том, что List<MyItem>
или любой Iterable
содержит два экземпляра MyItem
, чьи свойства "name"
имеют значения "foo"
и "bar"
. Если какие-либо другие свойства не совпадают, мне совершенно не нужны цели этого теста. Если имена совпадают, это успешный тест.
Я хотел бы, чтобы это было однострочным, если возможно. Вот какой-то "псевдо-синтаксис" того, что я хотел бы сделать.
assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});
Может ли Хэмкрест быть хорошим для такого рода вещей? Если да, то какова будет именно версия hamcrest моего псевдосинтакса выше?
Ответы
Ответ 1
Спасибо @Разван, который указал мне в правильном направлении. Я смог получить его в одной строке, и я успешно охотился на импорт для Hamcrest 1.3.
импорт:
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;
код:
assertThat( myClass.getMyItems(), contains(
hasProperty("name", is("foo")),
hasProperty("name", is("bar"))
));
Ответ 2
Try:
assertThat(myClass.getMyItems(),
hasItem(hasProperty("YourProperty", is("YourValue"))));
Ответ 3
Это не особенно Хамкрест, но я думаю, стоит упомянуть здесь. То, что я использую довольно часто в Java8, выглядит примерно так:
assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));
(Отредактировано для небольшого улучшения Родриго Маньяри. Это немного меньше подробностей. См. комментарии.)
Это может быть немного труднее читать, но мне нравится тип и рефакторинг безопасности.
Он также отлично подходит для тестирования нескольких свойств bean в комбинации. например с java-like && выражение в лямбда фильтра.
Ответ 4
Assertj хорош в этом.
import static org.assertj.core.api.Assertions.assertThat;
assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");
Большой плюс для assertj по сравнению с hamcrest - это простое использование кода.
Ответ 5
AssertJ предоставляет отличную функцию в extracting()
: вы можете передать Function
для извлечения полей. Он обеспечивает проверку во время компиляции.
Вы также можете легко определить размер в первую очередь.
Это дало бы:
import static org.assertj.core.api.Assertions;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName)
.containsExactlyInAnyOrder("foo", "bar");
containsExactlyInAnyOrder()
утверждает, что список содержит только эти значения в любом порядке.
Чтобы утверждать, что список содержит эти значения в любом порядке, но может содержать и другие значения, используйте contains()
:
.contains("foo", "bar");
В качестве примечания: чтобы утверждать несколько полей из элементов List
, с помощью AssertJ мы делаем это, помещая ожидаемые значения для каждого элемента в функцию tuple()
:
import static org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName, MyItem::getOtherValue)
.containsExactlyInAnyOrder(
tuple("foo", "OtherValueFoo"),
tuple("bar", "OtherValueBar")
);
Ответ 6
Пока ваш список является конкретным классом, вы можете просто вызвать метод contains(), если вы внедрили метод equals() в 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")));
Предполагается, что вы внедрили конструктор, который принимает значения, которые вы хотите утверждать. Я понимаю, что это не одна строка, но полезно знать, какое значение отсутствует, а не проверять оба момента.