Тестирование в Hamcrest, в котором существует только один элемент в списке с определенным свойством

С помощью Hamcrest мы можем легко проверить наличие по крайней мере одного элемента в списке с определенным свойством, например.

List<Pojo> myList = ....

MatcherAssert.assertThat(myList, Matchers.hasItem(Matchers.<Pojo>hasProperty("fieldName", Matchers.equalTo("A funny string")))));

где класс Pojo выглядит примерно так:

public class Pojo{
  private String fieldName;
}

Это хорошо, но как мне проверить, что в списке есть ровно один объект с указанными свойствами?


person JeanValjean    schedule 13.04.2015    source источник


Ответы (3)


Возможно, вам придется написать свой собственный сопоставитель для этого. (Я предпочитаю утверждения fest и Mockito, но раньше использовал Hamcrest...)

Например...

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.core.IsCollectionContaining;

public final class CustomMatchers {

    public static <T> Matcher<Iterable<? super T>> exactlyNItems(final int n, Matcher<? super T> elementMatcher) {
        return new IsCollectionContaining<T>(elementMatcher) {
            @Override
            protected boolean matchesSafely(Iterable<? super T> collection, Description mismatchDescription) {
                int count = 0;
                boolean isPastFirst = false;

                for (Object item : collection) {

                    if (elementMatcher.matches(item)) {
                        count++;
                    }
                    if (isPastFirst) {
                        mismatchDescription.appendText(", ");
                    }
                    elementMatcher.describeMismatch(item, mismatchDescription);
                    isPastFirst = true;
                }

                if (count != n) {
                    mismatchDescription.appendText(". Expected exactly " + n + " but got " + count);
                }
                return count == n;
            }
        };
    }
}

Теперь вы можете сделать...

    List<TestClass> list = Arrays.asList(new TestClass("Hello"), new TestClass("World"), new TestClass("Hello"));

    assertThat(list, CustomMatchers.exactlyNItems(2, hasProperty("s", equalTo("Hello"))));

Пример неудачного вывода, когда список...

    List<TestClass> list = Arrays.asList(new TestClass("Hello"), new TestClass("World"));

...будет...

Exception in thread "main" java.lang.AssertionError: 
Expected: a collection containing hasProperty("s", "Hello")
     but: , property 's' was "World". Expected exactly 2 but got 1

(Возможно, вы захотите немного изменить это)

Кстати, "TestClass"...

public static class TestClass {
    String s;

    public TestClass(String s) {
        this.s = s;
    }

    public String getS() {
        return s;
    }
}
person BretC    schedule 13.04.2015
comment
Было бы неплохо, если бы вы могли сделать это из коробки, я не вижу встроенных сопоставителей, которые бы это делали на данный момент! - person BretC; 13.04.2015

Вы также можете использовать Predicate<Pojo> и фильтр:

Predicate<Pojo> predicate = pojo -> pojo.getField().equals("funny string");

long nrOfElementsSatisfyingPredicate = myList.stream()
                                      .filter(predicate::test)
                                      .count();

assertEquals(1, nrOfElementsSatisfyingPredicate);
person Matthias Braun    schedule 15.08.2016
comment
Эй, спасибо за решение, но это не сработает с моим вопросом. Вы заставляете список иметь размер один, это не то, о чем я спрашивал. - person JeanValjean; 15.08.2016
comment
Спасибо за ваш комментарий, Роберто. Я неправильно понял вопрос. Я надеюсь, что этот ответ будет более полезным. - person Matthias Braun; 16.08.2016
comment
Привет Матиас, да, это работает. Но смысл был в том, чтобы использовать Hamcrest. Если вы вводите логику в тесты, то вы должны быть уверены, что она в порядке, иначе вам нужно тестирование еще и для нее. - person JeanValjean; 17.08.2016

person    schedule
comment
Я не понимаю, зачем мне создавать вторую коллекцию - person JeanValjean; 13.04.2015
comment
Я не слежу за вами, вам не нужно создавать две коллекции - person tddmonkey; 13.04.2015
comment
Вы сказали: что гарантирует, что две коллекции по существу одинаковы. Кроме того, содержит это не ответ. Это гарантирует, что список содержит именно предоставленные элементы. Из документа утверждение assertThat(Arrays.asList("foo", "bar"), contains("foo", "bar")) выполнено успешно, а assertThat(Arrays.asList("foo", "bar"), contains("foo")) не выполнено, так как я могу использовать его, чтобы быть уверенным, что оно содержит ровно один экземпляр foo? Я не могу, потому что я также должен заботиться обо всех других элементах в списке. - person JeanValjean; 14.04.2015