Chr*_*son 11 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()))
));
Run Code Online (Sandbox Code Playgroud)
当NameDto是普通班级时,这工作得很好。但是在我将其更改为 a 之后Record,HamcresthasProperty抱怨没有名为 的属性name:
java.lang.AssertionError:
Expected: a collection containing hasProperty("name", "Test Name")
but: mismatches were: [No property "name", No property "name"]
Run Code Online (Sandbox Code Playgroud)
是否有其他匹配器可以用来实现与以前相同的匹配?或者我可以使用其他一些解决方法来让它处理记录?
man*_*uti 11
记录字段的访问器方法不遵循常规的 JavaBeans 约定,因此User记录(比如public record User (String name) {})将有一个访问器方法,其名称name()不是getName()。
我怀疑这就是 Hamcrest 认为没有财产的原因。除了编写自定义 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);
}
}
Run Code Online (Sandbox Code Playgroud)
我发现仅使用AssertJ 就可以实现相同的测试,至少在本例中是这样:
assertThat(result.getUsers())
.extracting(UserDto::name)
.contains(user1.getName(), user2.getName());
Run Code Online (Sandbox Code Playgroud)
它没有使用hasProperty,所以它并不能完全解决问题。
| 归档时间: |
|
| 查看次数: |
510 次 |
| 最近记录: |