java - 如何使用 Java 记录断言 hasProperty?

标签 java unit-testing hamcrest java-record java-16

我在测试中有一段代码,使用 Hamcrest 2.2 检查结果列表是否包含某些属性:

assertThat(result.getUsers(), hasItem(
    hasProperty("name", equalTo(user1.getName()))
));
assertThat(result.getUsers(), hasItem(
    hasProperty("name", equalTo(user2.getName()))
));
NameDto 时,这工作得很好是普通类。但是在我把它改成 Record 之后, Hamcrest的hasProperty提示没有名为 name 的属性:
java.lang.AssertionError:
Expected: a collection containing hasProperty("name", "Test Name")
     but: mismatches were: [No property "name", No property "name"]
是否有其他匹配器可以用来实现与以前相同的匹配?或者我可以使用其他一些解决方法来让它处理记录?

最佳答案

记录字段的访问器方法不遵循常规的 JavaBeans 约定,因此 User记录(比如 public record User (String name) {} )将有一个访问器方法,其名称为 name()而不是 getName() .
我怀疑这就是 Hamcrest 认为没有属性(property)的原因。除了编写自定义 Matcher 之外,我认为在 Hamcrest 中没有开箱即用的方法。
这是一个自定义 HasRecordComponentWithValue灵感来自现有 HasPropertyWithValue .这里利用的主要实用程序是 Java 的 Class.getRecordComponents() :

public static class HasRecordComponentWithValue<T> extends TypeSafeDiagnosingMatcher<T> {
    private static final Condition.Step<RecordComponent,Method> WITH_READ_METHOD = withReadMethod();
    private final String componentName;
    private final Matcher<Object> valueMatcher;

    public HasRecordComponentWithValue(String componentName, Matcher<?> valueMatcher) {
        this.componentName = componentName;
        this.valueMatcher = nastyGenericsWorkaround(valueMatcher);
    }

    @Override
    public boolean matchesSafely(T bean, Description mismatch) {
        return recordComponentOn(bean, mismatch)
                  .and(WITH_READ_METHOD)
                  .and(withPropertyValue(bean))
                  .matching(valueMatcher, "record component'" + componentName + "' ");
    }

    private Condition.Step<Method, Object> withPropertyValue(final T bean) {
        return new Condition.Step<Method, Object>() {
            @Override
            public Condition<Object> apply(Method readMethod, Description mismatch) {
                try {
                    return matched(readMethod.invoke(bean, NO_ARGUMENTS), mismatch);
                } catch (Exception e) {
                    mismatch.appendText(e.getMessage());
                    return notMatched();
                }
            }
        };
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("hasRecordComponent(").appendValue(componentName).appendText(", ")
                   .appendDescriptionOf(valueMatcher).appendText(")");
    }

    private Condition<RecordComponent> recordComponentOn(T bean, Description mismatch) {
        RecordComponent[] recordComponents = bean.getClass().getRecordComponents();
        for(RecordComponent comp : recordComponents) {
            if(comp.getName().equals(componentName)) {
                return matched(comp, mismatch);
            }
        }
        mismatch.appendText("No record component \"" + componentName + "\"");
        return notMatched();
    }


    @SuppressWarnings("unchecked")
    private static Matcher<Object> nastyGenericsWorkaround(Matcher<?> valueMatcher) {
        return (Matcher<Object>) valueMatcher;
    }

    private static Condition.Step<RecordComponent,Method> withReadMethod() {
        return new Condition.Step<RecordComponent, java.lang.reflect.Method>() {
            @Override
            public Condition<Method> apply(RecordComponent property, Description mismatch) {
                final Method readMethod = property.getAccessor();
                if (null == readMethod) {
                    mismatch.appendText("record component \"" + property.getName() + "\" is not readable");
                    return notMatched();
                }
                return matched(readMethod, mismatch);
            }
        };
    }

    @Factory
    public static <T> Matcher<T> hasRecordComponent(String componentName, Matcher<?> valueMatcher) {
        return new HasRecordComponentWithValue<T>(componentName, valueMatcher);
    }
}

关于java - 如何使用 Java 记录断言 hasProperty?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66982522/

相关文章:

unit-testing - 如何编写 "dirty"单元测试?

android - UnitTesting Android TabActivity时获取Nullpointer异常

junit - Hamcrest - Matchers.hasProperty : how to check if a List of objects contains an object with a concrete value

java - 为多个主类创建1个jar文件

java - 使用 Maven AspectJ 编织依赖项时重复类

c# - 创建类访问器的实例

unit-testing - AllOf Hamcrest 与 Maven 匹配器

java - 比较 hamcrest 中的子字段

java - 如何使用带有 Web 身份验证的 apache httpclient 进行 http 发布?

java - 我们可以在 Android 表单中为 Android 组件使用 CSS 吗?