簡體   English   中英

Hamcrest:測試列表包含一個具有特定值的私有字段的項目

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

我有這個課:

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"我的測試用例item 0: No Property "x"

我該如何測試? 我唯一能想到的就是為getX()添加一個公共getter,然后遍歷返回的List並檢查每個元素。 請記住,雖然該方法返回一個singletonList ,返回類型只是List ,因此它可能在將來被改變為有它的多個值。

我認為首先值得一提的是,像這樣測試類內部不是一個好主意,除非在非常特殊的情況下。 您的測試將很脆弱,通常通常是完全安全的更改(即重命名字段)現在可能會導致自動構建失敗。 您應該測試外部行為 ,而不是實現細節。

似乎最好在類A實現equalshashCode ,因此您可以簡單地執行以下操作:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM