java - Hamcrest:测试列表包含具有特定值的私有字段的项目
问题描述
我有这堂课:
public class A {
private int x;
public A(int x) {
this.x = x;
}
}
还有一个我想测试的不同类中的方法:
public class B {
public List underTest() {
int x = doStuff();
return Collections.singletonList(new A(x));
}
private int doStuff() { /* ... */ }
}
我想测试一下,在underTest()
返回列表中的项目的末尾是否包含一个x
等于某个值的字段。我写了这个:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
@Test
public void Test1() {
List result = bInstance.underTest();
assertThat(result, contains(hasProperty("x", is(1))));
}
但是junit抱怨item 0: No Property "x"
我的测试用例。
我该如何测试呢?我唯一能想到的就是为 添加一个公共 getter getX()
,然后遍历返回List
并检查每个元素。请记住,虽然该方法返回 a singletonList
,但返回类型只是List
,因此将来可以将其更改为包含多个值。
解决方案
我认为首先值得说的是,像这样测试类内部并不是一个好主意,除非在非常特殊的情况下。您的测试将很脆弱,并且通常完全安全的更改 - 即重命名字段 - 现在可能会导致您的自动构建失败。您应该测试外部行为,而不是实现细节。
看起来你最好在你的 class 中实现equals
and ,所以你可以简单地做:hashCode
A
contains(new A(1))
话虽如此,如果您确实有充分的理由这样做(这种情况很少见),那么您就不能使用hasProperty
它。
从JavaDoc:
创建一个匹配器,当被检查对象具有具有指定名称且值满足指定匹配器的 JavaBean 属性时匹配。
我相信这意味着您需要一个名为getX
.
您不应该仅仅为了测试的目的而添加这样的方法,但是您可以编写自己的通用Matcher
实现,该实现将使用反射来检查类的字段。
这是一个示例实现:
class ReflectiveFieldMatcher<T> extends BaseMatcher<Object>
{
private final String fieldName;
private final T expectedValue;
ReflectiveFieldMatcher(final String fieldName, final T expectedValue)
{
this.fieldName = fieldName;
this.expectedValue = expectedValue;
}
@Override
public boolean matches(final Object obj)
{
for (final Field field : obj.getClass().getFields())
{
if (field.getName().equals(fieldName))
{
field.setAccessible(true);
try
{
Object value = field.get(obj);
return expectedValue.equals(value);
}
catch (final IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
}
return false;
}
@Override
public void describeTo(final Description description)
{
description.appendText("Object with field '" + fieldName + "' with value: " + expectedValue);
}
}
您的示例现在如下所示:
assertThat(result, contains(new ReflectiveFieldMatcher<>("x", 1)));
推荐阅读
- mysql - SQL 任务,如果产品在给定月份没有销售,则在本月显示 0
- javascript - Fullcalendar 事件颜色 MySQL
- playframework - 播放框架“runProd”不接受自定义配置文件
- c++ - 从 ostringstream 读取/写入会更改原始数据
- python - 使用 Dockerfile RUN 而不是 CMD 传递环境变量
- java - 如何启用firebase离线数据并将数据传递给recyclerview适配器?
- python - 是否可以在 Django 模板中过滤“相关字段”?
- php - 如果在数据库中找不到条目,我如何获得所需的值
- jquery - 用户单击链接并重定向时如何保持子菜单不折叠
- c# - 如何转换 ReadOnlyMemory
到只读存储器