在单元测试中,我想验证两个列表包含相同的元素。要测试的列表是Person
对象列表的构建,其中提取了一个String
类型的字段。另一个列表包含String
文字。
通常会找到以下代码片段来完成此任务(请参见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
类的定义为:
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>
或其他名称)进行比较的更直接或更有效的方法。
您的问题的代码未反映您在评论中描述的内容。在评论中,您说所有名称都应存在且大小应匹配,换句话说,仅顺序可以不同。
您的代码是
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
,第一个解决方案就不需要临时集,而后者则没有任何优势。
如果元素数必须相同,则最好比较集合:
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
更为方便,因为如果发生故障,错误消息将包含您的设置的字符串表示形式。
这是我如何解决两个Person列表的相等性的方法>
public class Person { private String name; //constructor, setters & getters @Override public boolean equals(Object o) { if(this == o) return true; if(o == null || getClass() != o.getClass()) return false Person p = (Person) o; return name.equals(p.name); } @Override public int hashCode() { return Objects.hash(name);} } // call this boolean method where (in a service for instance) you want to test the equality of 2 lists of Persons. public boolean isListsEqual(List<Person> givenList, List<Person> dbList) { if(givenList == null && dbList == null) return true; if(!givenList.containsAll(dbList) || givenList.size() != dbList.size()) return false; return true; } // You can test it in a main method or where needed after initializing 2 lists boolean equalLists = this.isListsEqual(givenList, dbList); if(equalLists) { System.out.println("Equal"); } else {System.out.println("Not Equal");}
我希望这可以帮助需要帮助的人。