1. 概述

Hamcrest 是一个提供匹配器(matchers)方法的库,能帮助开发者编写更简洁的单元测试。它包含大量匹配器,你可以先通过这篇文章了解基础用法。

本文将重点探讨Bean 匹配器——专门用于验证 POJO 对象属性的利器。

2. 环境配置

引入 Hamcrest 只需在 pom.xml 中添加以下 Maven 依赖:

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>java-hamcrest</artifactId>
    <version>2.2</version>
    <scope>test</scope>
</dependency>

最新版本可在 Maven Central 查询。

3. Bean 匹配器实战

Bean 匹配器是验证 POJO 属性的瑞士军刀,在单元测试中高频使用。先创建测试用的 City 类:

public class City {
    String name;
    String state;

    // 标准构造器、getter/setter
}

3.1. hasProperty 匹配器

核心功能:验证 Bean 是否包含指定名称的属性

@Test
public void givenACity_whenHasProperty_thenCorrect() {
    City city = new City("San Francisco", "CA");
    
    assertThat(city, hasProperty("state"));
}

测试通过,因为 City 类确实存在 state 属性。

进阶用法:同时验证属性值

@Test
public void givenACity_whenHasPropertyWithValueEqualTo_thenCorrect() {
    City city = new City("San Francisco", "CA");
        
    assertThat(city, hasProperty("name", equalTo("San Francisco")));
}

⚠️ 注意:hasProperty 支持嵌套匹配器,例如忽略大小写:

@Test
public void givenACity_whenHasPropertyWithValueEqualToIgnoringCase_thenCorrect() {
    City city = new City("San Francisco", "CA");

    assertThat(city, hasProperty("state", equalToIgnoringCase("ca")));
}

3.2. samePropertyValuesAs 匹配器

当需要批量验证多个属性时,创建期望对象比逐个断言更高效:

@Test
public void givenACity_whenSamePropertyValuesAs_thenCorrect() {
    City city = new City("San Francisco", "CA");
    City city2 = new City("San Francisco", "CA");

    assertThat(city, samePropertyValuesAs(city2));
}

❌ 反向验证示例:

@Test
public void givenACity_whenNotSamePropertyValuesAs_thenCorrect() {
    City city = new City("San Francisco", "CA");
    City city2 = new City("Los Angeles", "CA");

    assertThat(city, not(samePropertyValuesAs(city2)));
}

3.3. getPropertyDescriptor 工具方法

需要动态检查类结构时,这个工具方法能获取属性描述符:

@Test
public void givenACity_whenGetPropertyDescriptor_thenCorrect() {
    City city = new City("San Francisco", "CA");
    PropertyDescriptor descriptor = getPropertyDescriptor("state", city);

    assertThat(descriptor
      .getReadMethod()
      .getName(), is(equalTo("getState")));
}

PropertyDescriptor 对象包含属性元数据,这里我们验证了 getter 方法名。

3.4. propertyDescriptorsFor 工具方法

批量获取所有属性描述符,可指定类层级深度:

@Test
public void givenACity_whenGetPropertyDescriptorsFor_thenCorrect() {
    City city = new City("San Francisco", "CA");
    PropertyDescriptor[] descriptors = propertyDescriptorsFor(
      city, Object.class);
 
    List<String> getters = Arrays.stream(descriptors)
      .map(x -> x.getReadMethod().getName())
      .collect(toList());

    assertThat(getters, containsInAnyOrder("getName", "getState"));
}

关键步骤:

  1. 获取从 CityObject 层级的所有属性描述符
  2. 用 Java 8 Stream 提取 getter 方法名
  3. 通过集合匹配器验证结果(更多集合匹配器见这里

4. 总结

Hamcrest 匹配器是每个项目的必备工具,学习曲线平缓但见效极快。

Bean 匹配器尤其擅长简化 POJO 验证,这正是单元测试中的高频需求。掌握这些工具能显著提升测试代码的可读性和维护性。

完整示例代码请参考 GitHub 项目


原始标题:Hamcrest Bean Matchers