1. 概述

Hamcrest 提供了多种匹配器,让单元测试断言更简洁易读。 你可以在这里探索一些基础匹配器:Hamcrest 入门指南

本篇教程将深入讲解对象匹配器的使用技巧。

2. 环境配置

要使用 Hamcrest,只需在 pom.xml 中添加以下 Maven 依赖

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

最新版本可在 Maven 中央仓库 查询。

3. 对象匹配器

对象匹配器专门用于校验对象的属性。在深入之前,我们先创建两个示例类方便演示。

第一个类是 Location,没有任何属性:

public class Location {}

第二个类 City 继承自 Location,并添加了以下实现:

public class City extends Location {
    
    String name;
    String state;

    // 标准构造器、getter 和 setter

    @Override
    public String toString() {
        if (this.name == null && this.state == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        sb.append("Name: ");
        sb.append(this.name);
        sb.append(", ");
        sb.append("State: ");
        sb.append(this.state);
        sb.append("]");
        return sb.toString();
    }
}

注意 City 继承了 Location,这个关系后面会用到。现在开始探索对象匹配器!

3.1. hasToString

顾名思义,**hasToString 用于验证对象的 toString() 方法返回特定字符串**:

@Test
public void givenACity_whenHasToString_thenCorrect() {
    City city = new City("San Francisco", "CA");
    
    assertThat(city, hasToString("[Name: San Francisco, State: CA]"));
}

我们创建 City 对象并验证其 toString() 输出符合预期。更进一步,我们可以不检查完全相等,而是检查其他条件:

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

    assertThat(city, hasToString(
      equalToIgnoringCase("[NAME: SAN FRANCISCO, STATE: CA]")));
}

hasToString 支持两种重载形式

  • 直接传入字符串
  • 传入文本匹配器(如 equalToIgnoringCase

因此我们还能这样用:

@Test
public void givenACity_whenHasToStringEmptyOrNullString_thenCorrect() {
    City city = new City(null, null);
    
    assertThat(city, hasToString(emptyOrNullString()));
}

更多文本匹配器用法可参考:Hamcrest 文本匹配器。接下来看下一个对象匹配器。

3.2. typeCompatibleWith

这个匹配器用于验证 is-a 继承关系。现在轮到我们的 Location 父类登场了:

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

    assertThat(city.getClass(), is(typeCompatibleWith(Location.class)));
}

断言 CityLocation 的子类,显然成立。如果要验证非继承关系:

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

    assertThat(city.getClass(), is(not(typeCompatibleWith(String.class))));
}

City 当然不是 String 的子类。⚠️ 注意:所有 Java 对象都应通过以下测试:

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

    assertThat(city.getClass(), is(typeCompatibleWith(Object.class)));
}

is 匹配器本质是包装其他匹配器,目的是让断言语义更清晰。

4. 总结

Hamcrest 提供了简洁优雅的断言方式。丰富的匹配器库既能提升开发效率,又能增强代码可读性。

对象匹配器是校验类属性的利器,简单直接不踩坑。

完整实现代码请查阅 GitHub 项目


原始标题:Hamcrest Object Matchers