【问题标题】:Is there a Hamcrest "for each" Matcher that asserts all elements of a Collection or Iterable match a single specific Matcher?是否有一个 Hamcrest “for each” Matcher 断言 Collection 或 Iterable 的所有元素与单个特定 Matcher 匹配?
【发布时间】:2015-05-05 18:38:16
【问题描述】:

给定 Collection 或 Iterable 的项目,是否有任何 Matcher(或匹配器的组合)会断言每个项目都匹配单个 Matcher?

例如,给定这个项目类型:

public interface Person {
    public String getGender();
}

我想写一个断言,即Persons 集合中的所有项目都具有特定的gender 值。我在想这样的事情:

Iterable<Person> people = ...;
assertThat(people, each(hasProperty("gender", "Male")));

有什么方法可以在不自己编写 each 匹配器的情况下做到这一点?

【问题讨论】:

标签: java hamcrest


【解决方案1】:

使用Every 匹配器。

import org.hamcrest.beans.HasPropertyWithValue;
import org.hamcrest.core.Every;
import org.hamcrest.core.Is;
import org.junit.Assert;

Assert.assertThat(people, (Every.everyItem(HasPropertyWithValue.hasProperty("gender", Is.is("male")))));

Hamcrest 还提供Matchers#everyItem 作为该Matcher 的快捷方式。


完整示例

@org.junit.Test
public void method() throws Exception {
    Iterable<Person> people = Arrays.asList(new Person(), new Person());
    Assert.assertThat(people, (Every.everyItem(HasPropertyWithValue.hasProperty("gender", Is.is("male")))));
}

public static class Person {
    String gender = "male";

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

【讨论】:

  • 泛型似乎引起了问题。我遇到了一个编译问题,因为 assertThat() 需要参数类型 T, Matcher&lt;?super T&gt; 但它得到了 Iterable&lt;Person&gt;, Matcher&lt;Iterable&lt;Object&gt;&gt;
  • @E-Riz 我已经更新了一个完整的例子。如果您的不同,请编辑您的问题以包含它。
  • 您的示例仍然存在与泛型相关的编译问题,但仅在针对 JDK 7 编译时;使用 JDK 8 可以很好地编译。我不知道泛型规范在 7 和 8 之间发生了变化,但显然他们意识到编译器很愚蠢并修复了它。
  • 为了让它为 Java 7 编译,我必须像这样声明 hasProperty 匹配器:HasPropertyWithValue.&lt;Person&gt;hasProperty("gender", is("Male")) 这几乎破坏了 Hamcrest 应该提供的可读性改进:-(
  • 除此之外,哇,反射和字符串访问。我觉得超级丑。我宁愿在 Person::getGender() 上手动迭代集合和 assertThat() 而不是 ...
【解决方案2】:

恕我直言,这更具可读性:

people.forEach(person -> Assert.assertThat(person.getGender()), Is.is("male"));

【讨论】:

  • 这是反模式。断言不应放在循环内。
  • @PetarMitrovic 为什么不应该将断言放在循环内?
  • 简单地说,您将无法全面了解失败的断言,因为测试运行器会在遇到第一个失败的断言时立即退出。
【解决方案3】:

比批准的答案更具可读性,并且循环中没有单独的断言:

import static org.assertj.core.api.Assertions.assertThat;

assertThat(people).allMatch((person) -> {
  return person.gender.equals("male");
});

【讨论】:

  • 但那不是 Hamcrest
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 2010-09-14
相关资源
最近更新 更多