2015-05-19 56 views
8

在单元测试中,我想验证两个列表包含相同的元素。要测试的列表构建了一个Person对象列表,其中提取了String类型的一个字段。另一个列表包含String文字。Java 8:比较不同类型列表的更有效的方法?

人们通常发现下面的代码段来完成此任务(见this answer):

List<Person> people = getPeopleFromDatabasePseudoMethod(); 
List<String> expectedValues = Arrays.asList("john", "joe", "bill"); 

assertTrue(people.stream().map(person -> person.getName()).collect(Collectors.toList()).containsAll(expectedValues)); 

Person类是defiend为:

public class Person { 

    private String name; 
    private int age; 

    public String getName() { 
     return name; 
    } 

    public void setName(final String name) { 
     this.name = name; 
    } 

    // other getters and setters 
} 

在上面的例子中,人的列表(或人)转换为使用Java 8技术的字符串列表,并且以老式方式完成比较。

现在我想知道,是否有更直接或更有效的方式来使用其他Java 8语句进行比较,例如allMatch()或某些Predicate<T>或其他东西。

+0

为什么不使用[Hamcrest](http://hamcrest.org/)匹配器呢? – Makoto

+0

你真的想检查'containsAll'吗?那么列表的顺序和大小可能会有所不同? –

+0

@TagirValeev我想确保'List people'包含我通过比较其唯一名称在静态列表中指定的所有人员。所以列表的顺序可能不同,但为了成功断言,列表的大小应该是相同的。 –

回答

13

你的问题的代码并不反映你在评论中描述的内容。在评论中你说所有的名字都应该存在,并且大小应该匹配,换句话说,只有顺序可能不同。

您的代码是

List<Person> people = getPeopleFromDatabasePseudoMethod(); 
List<String> expectedValues = Arrays.asList("john", "joe", "bill"); 

assertTrue(people.stream().map(person -> person.getName()) 
       .collect(Collectors.toList()).containsAll(expectedValues)); 

缺乏用于people尺寸的测试,换句话说允许重复。此外,使用containsAll组合两个List非常低效。这是更好的,如果你使用它反映了你的意图集合类型,即有没有重复,不关心的订单,并具有有效的查找:

Set<String> expectedNames=new HashSet<>(expectedValues); 
assertTrue(people.stream().map(Person::getName) 
       .collect(Collectors.toSet()).equals(expectedNames)); 

与此解决方案,您不需要测试的如果它们匹配,则已经暗示这些集合具有相同的大小,只是顺序可能不同。

有不需要收集的persons名称的解决方案:

Set<String> expectedNames=new HashSet<>(expectedValues); 
assertTrue(people.stream().allMatch(p->expectedNames.remove(p.getName())) 
      && expectedNames.isEmpty()); 

但如果expectedNames是创造出预期的名字的静态集合的一组临时它才会起作用。只要你决定用Set替代你的静态收集,第一个解决方案不需要临时设置,后者对它没有任何优势。

+0

我承认我也检查了列表的大小,但我没有写在问题的代码中。你说的是使用集合而不是列表。你的第二个解决方案就是我期望得到的。但正如你所说,你的第一个解决方案没有优势,我选择了这个。但是现在我使用'assertEquals'而不是'assertTrue'。 –

4

如果元素的数量必须相同,那么这将是更好地对比组:

List<Person> people = getPeopleFromDatabasePseudoMethod(); 
Set<String> expectedValues = new HashSet<>(Arrays.asList("john", "joe", "bill")); 
assertEquals(expectedValues, 
    people.stream().map(Person::getName).collect(Collectors.toSet())); 

的正确实施集的equals方法应该能够比较的套不同类型的:它只是检查内容是否相同(忽略当然的顺序)。

使用assertEquals更方便,因为在失败的情况下,错误消息将包含您的集合的字符串表示形式。

+0

是的,使用套装绝对有意义。 –