在单元测试中,我想验证两个列表是否包含相同的元素。要测试的列表是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>
或其他。
答案 0 :(得分:18)
您的问题代码未反映您在评论中描述的内容。在评论中,您说所有名称都应该存在且大小应该匹配,换句话说,只有订单可能不同。
您的代码是
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
替换静态集合,第一个解决方案不需要临时集合,后者没有优势。
答案 1 :(得分: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
更方便,因为如果失败,错误消息将包含您的集合的字符串表示。
答案 2 :(得分:0)
这就是我解决了两个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");}
我希望这可以帮助需要帮助的人。