我在测试中有一段代码,使用 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/