Hamcrest matcher для проверки возвращаемого значения метода в коллекции

hasProperty может использоваться с hasItem для проверки значения данного свойства, например:

Matcher hasName = Matchers<Person>hasProperty("name", is("Winkleburger"));
assertThat(names, hasItem(hasName));

Это прекрасно, когда имя является свойством, т.е. существует метод под названием getName().

Есть ли помощник, который будет проверять метод, который не является свойством? то есть: в этом случае он проверяет возвращаемое значение метода name(), а не getName(), для элементов в коллекции.

Ответ 1

Для этого вы можете использовать другой встроенный Hamcrest, FeatureMatcher. Они предназначены для объединения с другими помощниками после того, как они преобразуют ваш вклад в нечто другое. Поэтому в вашем случае вы сделаете что-то вроде этого:

@Test
public void test1() {
    List<Person> names = new ArrayList<>();
    names.add(new Person("Bob"));
    names.add(new Person("i"));

    assertThat(names, hasItem(name(equalTo("Winkleburger"))));
}

private FeatureMatcher<Person, String> name(Matcher<String> matcher) {
    return new FeatureMatcher<Person, String>(matcher, "name", "name") {
        @Override
        protected String featureValueOf(Person actual) {
            return actual.name();
        }
    };
}

Преимущество, которое вы получите с помощью этого пользовательского совпадения, состоит в том, что он полностью повторно используется и может быть скомпонован с другими помощниками, поскольку все, что он делает, - это извлечение данных, а затем отбрасывает любой другой подходящий помощник. Вы также получите соответствующую диагностику, например. в приведенном выше примере вы будете, если вы измените утверждение на значение, которое вы не получите:

java.lang.AssertionError: 
    Expected: a collection containing name "Batman"
    but: name was "Bob", name was "Winkleburger"

Ответ 2

Вы можете написать его самостоятельно:

public class HasName extends TypeSafeMatcher<MyClass> {
    private String expectedName;

    private HasName(String expectedName) {
        this.expectedName = expectedName;
    }

    @Override
    public boolean matchesSafely(MyClass obj) {
        return expectedName.equals(obj.name());
    }

    @Factory
    public static Matcher<MyClass> hasName(String expectedName) {
        return new HasName(expectedName);
    }
}

Где MyClass - это класс или интерфейс, который определяет метод name().