【问题标题】:Testing in Hamcrest that exists only one item in a list with a specific property在具有特定属性的列表中仅存在一项的 Hamcrest 测试
【发布时间】:2015-04-13 15:40:41
【问题描述】:

使用 Hamcrest,我们可以轻松测试列表中是否存在至少一个具有特定属性的项目,例如

List<Pojo> myList = ....

MatcherAssert.assertThat(myList, Matchers.hasItem(Matchers.<Pojo>hasProperty("fieldName", Matchers.equalTo("A funny string")))));

Pojo 类类似于:

public class Pojo{
  private String fieldName;
}

这很好,但是我如何检查列表中是否只有一个具有特定属性的对象?

【问题讨论】:

    标签: java unit-testing hamcrest


    【解决方案1】:

    您可能需要为此编写自己的匹配器。 (我更喜欢 fest assertions 和 Mockito,但习惯使用 Hamcrest...)

    例如...

    import org.hamcrest.Description;
    import org.hamcrest.Matcher;
    import org.hamcrest.core.IsCollectionContaining;
    
    public final class CustomMatchers {
    
        public static <T> Matcher<Iterable<? super T>> exactlyNItems(final int n, Matcher<? super T> elementMatcher) {
            return new IsCollectionContaining<T>(elementMatcher) {
                @Override
                protected boolean matchesSafely(Iterable<? super T> collection, Description mismatchDescription) {
                    int count = 0;
                    boolean isPastFirst = false;
    
                    for (Object item : collection) {
    
                        if (elementMatcher.matches(item)) {
                            count++;
                        }
                        if (isPastFirst) {
                            mismatchDescription.appendText(", ");
                        }
                        elementMatcher.describeMismatch(item, mismatchDescription);
                        isPastFirst = true;
                    }
    
                    if (count != n) {
                        mismatchDescription.appendText(". Expected exactly " + n + " but got " + count);
                    }
                    return count == n;
                }
            };
        }
    }
    

    你现在可以做...

        List<TestClass> list = Arrays.asList(new TestClass("Hello"), new TestClass("World"), new TestClass("Hello"));
    
        assertThat(list, CustomMatchers.exactlyNItems(2, hasProperty("s", equalTo("Hello"))));
    

    列表为...时的失败输出示例

        List<TestClass> list = Arrays.asList(new TestClass("Hello"), new TestClass("World"));
    

    ...将会...

    Exception in thread "main" java.lang.AssertionError: 
    Expected: a collection containing hasProperty("s", "Hello")
         but: , property 's' was "World". Expected exactly 2 but got 1
    

    (您可能想稍微自定义一下)

    顺便说一句,“TestClass”是……

    public static class TestClass {
        String s;
    
        public TestClass(String s) {
            this.s = s;
        }
    
        public String getS() {
            return s;
        }
    }
    

    【讨论】:

    • 如果你能开箱即用就太好了,我目前看不到任何内置的匹配器可以做到这一点!
    【解决方案2】:

    Matchers.hasItems 专门检查您提供的项目是否存在于集合中,您正在寻找的是Matchers.contains,它确保两个集合基本相同 - 或者在您的情况下,根据假如

    【讨论】:

    • 我不明白为什么要创建第二个集合
    • 我不关注你,你不必创建两个集合
    • 您说:“这确保了 2 个集合本质上是相同的”。除此之外,contains 不是答案。它确保列表准确包含所提供的元素。从文档中,断言assertThat(Arrays.asList("foo", "bar"), contains("foo", "bar")) 成功,而assertThat(Arrays.asList("foo", "bar"), contains("foo")) 失败,那么我如何使用它来确保它只包含一个“foo”实例?我不能,因为我还应该关心列表中的所有其他元素
    【解决方案3】:

    您也可以使用Predicate&lt;Pojo&gt;filter

    Predicate<Pojo> predicate = pojo -> pojo.getField().equals("funny string");
    
    long nrOfElementsSatisfyingPredicate = myList.stream()
                                          .filter(predicate::test)
                                          .count();
    
    assertEquals(1, nrOfElementsSatisfyingPredicate);
    

    【讨论】:

    • 嘿,感谢您的解决方案,但这不适用于我的问题。您强制列表大小为 1,这不是我要的。
    • 感谢您的评论,罗伯托。我误解了这个问题。我希望这个答案更有帮助。
    • 嗨,马蒂亚斯,是的,这行得通。但重点是使用 Hamcrest。如果你在测试中引入逻辑,那么你必须确保它是好的,否则你也需要对其进行测试。
    猜你喜欢
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多