简体   繁体   English

Hamcrest:测试列表包含一个具有特定值的私有字段的项目

[英]Hamcrest: test list contains an item that has a private field with a certain value

I have this class: 我有这个课:

public class A {
    private int x;

    public A(int x) {
        this.x = x;
    }
}

And a method in a different class I want to test: 还有我要测试的其他类中的方法:

public class B {
    public List underTest() {
        int x = doStuff();
        return Collections.singletonList(new A(x));
    }

    private int doStuff() { /* ... */ }
}

I want to test that, at the end of underTest() , the item in the returned list contains an x field equal to a certain value. 我想测试一下,在underTest()的末尾,返回列表中的项包含等于某个值的x字段。 I've written this: 我写了这个:

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))));
}

But junit complains that item 0: No Property "x" for my test case. 但是junit抱怨item 0: No Property "x"我的测试用例item 0: No Property "x"

How can I test this? 我该如何测试? The only thing I can think of is to add a public getter for getX() , then iterate through the returned List and check every element. 我唯一能想到的就是为getX()添加一个公共getter,然后遍历返回的List并检查每个元素。 Remember that, while the method returns a singletonList , the return type is just List , so it could be changed in the future to have multiple values in it. 请记住,虽然该方法返回一个singletonList ,返回类型只是List ,因此它可能在将来被改变为有它的多个值。

I think it's first worth saying that testing class internals like this is not a good idea, except maybe in very special cases. 我认为首先值得一提的是,像这样测试类内部不是一个好主意,除非在非常特殊的情况下。 Your tests will be brittle and changes that would normally be totally safe - ie renaming a field - may now cause your automated build to fail. 您的测试将很脆弱,通常通常是完全安全的更改(即重命名字段)现在可能会导致自动构建失败。 You should test external behaviour , not implementation details. 您应该测试外部行为 ,而不是实现细节。

It seems like you'd be better off implementing equals and hashCode in your class A , so then you can simply do: 似乎最好在类A实现equalshashCode ,因此您可以简单地执行以下操作:

contains(new A(1))

With that said, if you do have a genuinely good reason to do this (and such cases will be rare) then you cannot use hasProperty for this. 话虽如此,如果您确实有充分的理由这样做(这种情况很少见),则不能为此使用hasProperty

From the JavaDoc : JavaDoc

Creates a matcher that matches when the examined object has a JavaBean property with the specified name whose value satisfies the specified matcher. 创建一个匹配项,该匹配项在被检查对象具有具有指定名称的JavaBean属性且其值满足指定匹配项时匹配。

I believe this implies that you would need a method named getX . 我相信这意味着您将需要一个名为getX的方法。

You shouldn't add such a method just for the purpose of a test, but you can write your own general-purpose Matcher implementation that will use reflection to examine the fields of the class. 您不应该只是为了测试目的而添加这种方法,而是可以编写自己的通用Matcher实现,该实现将使用反射来检查类的字段。

Here is a sample implementation: 这是一个示例实现:

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);
    }
}

Your example would now look like this: 您的示例现在如下所示:

assertThat(result, contains(new ReflectiveFieldMatcher<>("x", 1)));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 检查对象列表中的字段是否具有特定值? - Checking that a field in a List of Objects has a certain value? Hamcrest Matchers包含匹配列表 - Hamcrest Matchers contains with List of matchers Java Hamcrest:Collection包含类型的项目 - Java Hamcrest : Collection contains item of type Hamcrest 有没有办法测试一个值是否为数字? - Is there a way in Hamcrest to test for a value to be a number? JPA规范:选择列表属性包含具有特定值的项目的项目 - JPA Specifications: Select items where list attribute contains item with certain value Hamcrest或assertj:具有要求的列表中的测试元素 - Hamcrest or assertj : test element in list with requirements 使用 REST 和 Java Hamcrest 检查数组是否包含具有多个键值对的项目,其中值具有不同的类型 - Using REST assured with Java Hamcrest to check if Array contains item with multiple key value pairs where the values have a different type 我可以检查 List 是否包含一个对象,该对象具有在 java 中具有特定值的字段吗? - Can I check whether a List contains an object that has fields with a certain value in java? Hamcrest测试地图包含来自另一个地图的所有条目 - Hamcrest test that a map contains all entries from another map Java Hamcrest Matcher 检查列表是否包含另一个列表 - Java Hamcrest Matcher check if list contains another list
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM