使用 assertThat 测试列表列表是否包含特定元素

Test if list of lists contains specific element using assertThat

我尝试使用 Assert#assertThat 检查列表列表中的每个列表是否包含特定值。

我写了这段代码,但它不起作用。 测试未编译,代码带有红线下划线并显示错误消息(查看注释):

    List<List<String>> testedList = new ArrayList<>();

    List<String> firstList = new ArrayList<>();
    firstList.add("1");
    firstList.add("2");

    List<String> secondList = new ArrayList<>();
    secondList.add("2");
    secondList.add("3");

    testedList.add(firstList);
    testedList.add(secondList);

    Assert.assertThat(testedList, CoreMatchers.everyItem(CoreMatchers.hasItem("2")));
    //          Required type       Provided
    // actual:  T                   List<java.util.List<java.lang.String>>
    // matcher: Matcher<? super T>  Matcher<Iterable<Iterable<? super String>>>

甚至使用显式类型:

    Assert.assertThat(testedList, CoreMatchers.<List<String>>everyItem(CoreMatchers.<String>hasItem("2")));
    // Required type: Matcher<List<String>> 
    // Provided:      Matcher<Iterable<? super String>>

如果它只是字符串列表,我可以检查每个字符串是否包含特定的字母:

    List<String> testedList = new ArrayList<>();

    testedList.add("1a");
    testedList.add("2a");

    Assert.assertThat(testedList, CoreMatchers.everyItem(CoreMatchers.containsString("a")));

那么我的代码有什么问题? 我该如何解决?

进口:

import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;

import java.util.List;
import java.util.ArrayList;

Gradle 依赖关系:

testCompile group: 'junit', name: 'junit', version: '4.12'

希望对您有所帮助,我尝试了另一种搜索元素的方法。我使用嵌套的 foreach 循环来查看列表列表是否包含该特定元素。

    List<List<String>> testedList = new ArrayList<>();
    boolean exist = false;

    List<String> firstList = new ArrayList<>();
    firstList.add("1");
    firstList.add("2");

    List<String> secondList = new ArrayList<>();
    secondList.add("2");
    secondList.add("3");

    testedList.add(firstList);
    testedList.add(secondList);

    for(List <String> e : testedList){
        for(String i : e){
        if(i.equalsIgnoreCase("2"))
            exist = true;
        }
    }System.out.println(exist);`

我认为 everyItem 匹配器不是为 hasItem 设计的,你已经发现你陷入了泛型地狱。

除了定义一个将“封装”泛型限制并将委托给 hasItem 匹配器的匹配器之外,我没有看到一个简单的解决方案。幸运的是,定义一个新的匹配器确实是一件容易的事。看看:

private class HasItemMatcher<T> extends BaseMatcher<List<T>> {

        private final Matcher<Iterable<? super T>> iterableMatcher;
        public HasItemMatcher(T value) {
            this.iterableMatcher = CoreMatchers.hasItem(value);
        }

        @Override
        public boolean matches(Object item) {
            return iterableMatcher.matches(item);
        }

        @Override
        public void describeTo(Description description) {
            iterableMatcher.describeTo(description);
        }
    }

这段代码是不言自明的。它将所有工作委托给现有的匹配器。

考虑到这一点,您可以将测试重写为:

    @Test
    public void sampleTest() {
        List<List<String>> testedList = new ArrayList<>();

        List<String> firstList = new ArrayList<>();
        firstList.add("1");
        firstList.add("2");

        List<String> secondList = new ArrayList<>();
        secondList.add("2");
        secondList.add("3");

        testedList.add(firstList);
        testedList.add(secondList);

        Assert.assertThat(testedList, CoreMatchers.everyItem(new HasItemMatcher<>("2")));
    }