Hamcrest 介绍

Hamcrest(官网)是一个用于编写匹配器(matcher)对象的框架,允许以声明的方式定义“匹配(match)”规则。它可以与 JUnit 框架配合使用,使断言可读更高、更加灵活(例如判断数组、集合、Map 中的内容等)。

Hamcrest 支持多种语言,本文只使用 JAVA 语言。

Maven 依赖示例:

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

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
    <scope>provided</scope>
</dependency>

Hamcrest 常用匹配器
import lombok.Data;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public class Demo {

    @Test
    public void testAssertThatWithHamcrest() {

        /**
         * 核心:
         */
        // anything:总是匹配
        assertThat("随便是个啥", anything("总是匹配就完事了"));
        
        // describedAs:添加一个定制的失败表述装饰器
        assertThat("zs", describedAs("自定义故障描述", equalTo("zs")));
        
        // is:改进可读性装饰器,底层is(equalTo(value))
        assertThat("zs", is("zs"));

        /**
         * 文本:
         */
        // equalToIgnoringCase:测试字符串相等忽略大小写
        assertThat("Foo", equalToIgnoringCase("FOO"));

        // equalToIgnoringWhiteSpace:测试字符串忽略空白
        assertThat("   my\tfoo  bar ", equalToIgnoringWhiteSpace(" my foo bar"));

        // containsString、endsWith、startsWith:测试字符串匹配
        assertThat("myStringOfNote", containsString("ring"));
        assertThat("myStringOfNote", endsWith("Note"));
        assertThat("myStringOfNote", startsWith("my"));
        
        /**
         *  逻辑:
         */
        // allOf:所有匹配器都匹配才匹配,相当于 &&
        // startsWith:匹配字符串以 XX 开头
        // containsString:匹配是否包含指定字符串
        assertThat("张三", allOf(startsWith("张"), containsString("三")));
        
        // anyOf:任何匹配器匹配就匹配,相当于 ||
        assertThat("张三", anyOf(startsWith("李"), containsString("三")));
        
        // not:包装的匹配器不匹配器时匹配,相当于与取反
        assertThat("tom", not("lucy"));

        /**
         *  对象:
         */
        // equalTo:测试对象相等使用 Object.equals 方法
        assertThat("foo", equalTo("foo"));
        
        // hasToString:测试 Object.toString 方法
        assertThat(true, hasToString(equalTo("true")));
        
        // instanceOf、typeCompatibleWith:测试类型
        assertThat("string", instanceOf(String.class));
        
        assertThat(Integer.class, typeCompatibleWith(Number.class));
        
        // notNullValue、nullValue:测试 null
        assertThat(null, nullValue());
        assertThat("", notNullValue());
        
        // sameInstance:测试对象实例
        Integer number = new Integer(200);
        assertThat(number, sameInstance(number));

        /**
         *  Beans:
         */
        @Data
        class MyClass{
            private String name;
        }
        // hasProperty:测试 JavaBeans 属性
        assertThat(new MyClass(), hasProperty("name"));

        /**
         *  集合:
         */
        // array:测试一个数组元素, 每一项是否匹配
        assertThat(new Integer[]{1, 2, 3}, is(array(equalTo(1), equalTo(2), equalTo(3))));
        
        // hasEntry、hasKey、hasValue:测试一个Map包含一个实体, 键或者值
        Map<String, Integer> map = new HashMap<>();
        map.put("张三", 23);
        map.put("李四", 24);
        assertThat(map, hasEntry("张三", 23));
        assertThat(map, hasKey("李四"));
        assertThat(map, hasValue(23));
        
        // hasItem、hasItems:测试一个集合包含一个元素
        assertThat(Arrays.asList("foo", "bar"), hasItem(startsWith("ba")));
        assertThat(Arrays.asList("foo", "bar", "baz"), hasItems(endsWith("z"), endsWith("o")));
        
        // hasItemInArray:测试一个数组包含一个元素
        assertThat(new String[]{"foo", "bar"}, hasItemInArray(startsWith("ba")));

        /**
         * 数字:
         */
        //  closeTo:测试浮点值接近给定的值,该匹配器在 +/- error 范围内匹配
        assertThat(1.03, is(closeTo(1.0, 0.04)));
        
        // greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo:测试次序
        assertThat(2, greaterThan(1));
        assertThat(1, greaterThanOrEqualTo(1));
        assertThat(1, lessThan(2));
        assertThat(1, lessThanOrEqualTo(1));

    }

}

自定义匹配器
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

/**
 * 自定义匹配器,判断年龄范围在 [1,200] 返回 true
 * 1、继承 TypeSafeMatcher 并指定泛型
 * 2、重写 matchesSafely、describeTo 方法
 * 3、提供外部调用的静态方法
 */
public class IsNormalAgeRange extends TypeSafeMatcher<Integer> {

    @Override
    public boolean matchesSafely(Integer number) {
        return number >=1 && number <= 200;
    }
    
    @Override
    public void describeTo(Description description) {
        description.appendText("need to be within [1, 200]");
    }

    public static Matcher normalAgeRange() {
        return new IsNormalAgeRange();
    }

}

测试:

@Test
public void testMyMatcher() {
    assertThat(100, IsNormalAgeRange.normalAgeRange());
}