在Junit 中断言 2 个 list 是否相等

如何在 JUnit 测试用例中判断 2 个列表是否相等? 我指的是列表中的内容之间是否相等。

例如:

List numbers = Arrays.asList("one", "two", "three");
List numbers2 = Arrays.asList("one", "two", "three");
List numbers3 = Arrays.asList("one", "two", "four");


// numbers should be equal to numbers2
//numbers should not be equal to numbers3
290417 次浏览

这是一个遗留的答案,适用于JUnit 4.3及以下版本。现代版本的JUnit在assertThat方法中包含了内置的可读失败消息。如果可能的话,最好选择其他答案。

List<E> a = resultFromTest();
List<E> expected = Arrays.asList(new E(), new E(), ...);
assertTrue("Expected 'a' and 'expected' to be equal."+
"\n  'a'        = "+a+
"\n  'expected' = "+expected,
expected.equals(a));

为了记录,正如@Paul在他对这个答案的评论中提到的,两个__abc是相等的:

当且仅当指定的对象也是一个列表时,两个列表的大小相同,并且两个列表中所有对应的元素对都相等。(如果(e1==null ? e2==null : e1.equals(e2)),则两个元素e1e2相等。)换句话说,如果两个列表以相同的顺序包含相同的元素,则定义为相等。这个定义确保equals方法在List接口的不同实现之间正常工作。

参见List接口的JavaDocs

junit4 !junit5这个问题值得一个新的答案。

我意识到这个答案是在这个问题之后几年写的,可能当时还没有这个功能。但是现在,这样做很简单:

@Test
public void test_array_pass()
{
List<String> actual = Arrays.asList("fee", "fi", "foe");
List<String> expected = Arrays.asList("fee", "fi", "foe");


assertThat(actual, is(expected));
assertThat(actual, is(not(expected)));
}

如果你安装了最新版本的Junit和hamcrest,只需添加这些导入:

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

http://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat(T, org. hamcreth . matcher) .

http://junit.org/junit4/javadoc/latest/org/hamcrest/CoreMatchers.html

http://junit.org/junit4/javadoc/latest/org/hamcrest/core/Is.html

如果你不关心元素的顺序,我建议在junit-addons中使用ListAssert.assertEquals

链接:http://junit-addons.sourceforge.net/

对于懒惰的Maven用户:

    <dependency>
<groupId>junit-addons</groupId>
<artifactId>junit-addons</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>

如果你不想建立一个数组列表,你也可以试试这个

@Test
public void test_array_pass()
{
List<String> list = Arrays.asList("fee", "fi", "foe");
Strint listToString = list.toString();
Assert.assertTrue(listToString.contains("[fee, fi, foe]"));   // passes
}

不转换为字符串并进行比较。这对性能不好。 在junit中,在Corematchers中,有一个=> hasItems

的匹配器
List<Integer> yourList = Arrays.asList(1,2,3,4)
assertThat(yourList, CoreMatchers.hasItems(1,2,3,4,5));

这是我所知道的检查列表中元素的更好的方法。

List<Integer> figureTypes = new ArrayList<Integer>(
Arrays.asList(
1,
2
));


List<Integer> figureTypes2 = new ArrayList<Integer>(
Arrays.asList(
1,
2));


assertTrue(figureTypes .equals(figureTypes2 ));

我不知道以上所有的答案都给出了比较两个对象列表的确切解决方案。 以上大多数方法只在比较的限制下有用 -尺寸比较 -参考比较

但如果我们有相同大小的对象列表,而对象级别上的数据不同,那么这种比较方法就没有帮助了。

我认为下面的方法可以在用户定义的对象上覆盖equals和hashcode方法。

我使用Xstream lib来覆盖equals和hashcode,但我们也可以通过out won logic /comparison来覆盖equals和hashcode。

这里有一个例子供你参考

    import com.thoughtworks.xstream.XStream;


import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;


class TestClass {
private String name;
private String id;


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


public String getName() {
return this.name;
}


public String getId() {
return id;
}


public void setId(String id) {
this.id = id;
}


/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
XStream xstream = new XStream();
String oxml = xstream.toXML(o);
String myxml = xstream.toXML(this);


return myxml.equals(oxml);
}


/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
XStream xstream = new XStream();
String myxml = xstream.toXML(this);
return myxml.hashCode();
}
}


public class XstreamCompareTest {
public static void main(String[] args) throws ParseException {
checkObjectEquals();
}


private static void checkObjectEquals() {
List<TestClass> testList1 = new ArrayList<TestClass>();
TestClass tObj1 = new TestClass();
tObj1.setId("test3");
tObj1.setName("testname3");
testList1.add(tObj1);


TestClass tObj2 = new TestClass();
tObj2.setId("test2");
tObj2.setName("testname2");
testList1.add(tObj2);


testList1.sort((TestClass t1, TestClass t2) -> t1.getId().compareTo(t2.getId()));


List<TestClass> testList2 = new ArrayList<TestClass>();
TestClass tObj3 = new TestClass();
tObj3.setId("test3");
tObj3.setName("testname3");
testList2.add(tObj3);


TestClass tObj4 = new TestClass();
tObj4.setId("test2");
tObj4.setName("testname2");
testList2.add(tObj4);


testList2.sort((TestClass t1, TestClass t2) -> t1.getId().compareTo(t2.getId()));


if (isNotMatch(testList1, testList2)) {
System.out.println("The list are not matched");
} else {
System.out.println("The list are matched");
}


}


private static boolean isNotMatch(List<TestClass> clist1, List<TestClass> clist2) {
return clist1.size() != clist2.size() || !clist1.equals(clist2);
}
}

最重要的是,如果不希望在对象的相等检查中包含任何字段,可以通过Annotation (@XStreamOmitField)忽略这些字段。有很多这样的注释需要配置,所以请深入了解这个库的注释。

我相信这个答案会节省你的时间来确定比较两个对象列表的正确方法:)。如果你看到任何问题,请评论。

你可以在junit中使用assertequal

import org.junit.Assert;
import org.junit.Test;


@Test
public void test_array_pass()
{
List<String> actual = Arrays.asList("fee", "fi", "foe");
List<String> expected = Arrays.asList("fee", "fi", "foe");
Assert.assertEquals(actual,expected);
}

如果元素的顺序不同,则返回错误。

如果你断言一个模型对象列表,那么你应该

.

.
    @Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj != null && obj instanceof ModelName) {
ModelName other = (ModelName) obj;
return this.getItem().equals(other.getItem()) ;
}
return false;
}

其他答案中提出的来自JUnit4/JUnit 5的assertEquals(Object, Object)或来自Hamcrest的assertThat(actual, is(expected));仅当equals()toString()都被比较对象的类(和深度)覆盖时才有效。

这很重要,因为断言中的相等测试依赖于equals(),而测试失败消息依赖于比较对象的toString() 对于内置类,如StringInteger等,用于…没问题,因为它们覆盖了equals()toString()。因此,使用assertEquals(Object,Object)断言List<String>List<Integer>是完全有效的 关于这个问题:你必须在类中重写equals(),因为它在对象相等方面是有意义的,而不仅仅是为了在JUnit测试中更容易地断言 为了使断言更容易,你有其他方法 作为一个好的实践,我喜欢断言/匹配器库。< / p >

下面是一个AssertJ解决方案。

org.assertj.core.api.ListAssert.containsExactly()是你所需要的:它验证实际的组恰好包含给定的值,而不包含其他任何值,按照javadoc中声明的顺序。

假设有一个Foo类,你可以在其中添加元素,并从那里获取元素 Foo的单元测试断言两个列表具有相同的内容,可能如下:

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;


@Test
void add() throws Exception {
Foo foo = new Foo();
foo.add("One", "Two", "Three");
Assertions.assertThat(foo.getElements())
.containsExactly("One", "Two", "Three");
}

AssertJ的一个优点是,按照预期声明List是不必要的:它使断言更直接,代码更可读:

Assertions.assertThat(foo.getElements())
.containsExactly("One", "Two", "Three");
但是断言/匹配器库是必须的,因为它们真的会进一步 现在假设Foo不存储__abc1,而是存储Bars实例 这是一种非常普遍的需求。 使用AssertJ,断言仍然很容易编写。你可以断言列表内容是相等的,即使元素的类没有覆盖equals()/hashCode(),而JUnit方式要求:

import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;


@Test
void add() throws Exception {
Foo foo = new Foo();
foo.add(new Bar(1, "One"), new Bar(2, "Two"), new Bar(3, "Three"));
Assertions.assertThat(foo.getElements())
.extracting(Bar::getId, Bar::getName)
.containsExactly(tuple(1, "One"),
tuple(2, "Two"),
tuple(3, "Three"));
}

我知道已经有很多选项来解决这个问题,但我宁愿对以任意顺序断言两个列表执行以下操作:

assertTrue(result.containsAll(expected) && expected.containsAll(result))

assertEquals(expected, result);适合我。 由于这个函数有两个对象,你可以将任何对象传递给它

public static void assertEquals(Object expected, Object actual) {
AssertEquals.assertEquals(expected, actual);
}

对于JUnit 5

你可以使用assertIterableEquals:

List<String> numbers = Arrays.asList("one", "two", "three");
List<String> numbers2 = Arrays.asList("one", "two", "three");


Assertions.assertIterableEquals(numbers, numbers2);

assertArrayEquals,并将列表转换为数组:

List<String> numbers = Arrays.asList("one", "two", "three");
List<String> numbers2 = Arrays.asList("one", "two", "three");
Assertions.assertArrayEquals(numbers.toArray(), numbers2.toArray());

您提到您对列表内容的相等感兴趣(但没有提到顺序)。所以containsExactlyInAnyOrder from AssertJ是一个很好的匹配。例如,它与spring-boot-starter-test打包在一起。

AssertJ docs ListAssert#containsExactlyInAnyOrder:

验证实际的组恰好包含给定的值,而不包含其他任何顺序。 例子:< / p >

 // an Iterable is used in the example but it would also work with an array
Iterable<Ring> elvesRings = newArrayList(vilya, nenya, narya, vilya);


// assertion will pass
assertThat(elvesRings).containsExactlyInAnyOrder(vilya, vilya, nenya, narya);


// assertion will fail as vilya is contained twice in elvesRings.
assertThat(elvesRings).containsExactlyInAnyOrder(nenya, vilya, narya);

如果没有重复,下面的代码应该可以完成这项工作

    Assertions.assertTrue(firstList.size() == secondList.size()
&& firstList.containsAll(secondList)
&& secondList.containsAll(firstList));

请注意:在重复的情况下,如果两个列表中的元素数量相同,则断言将通过(即使每个列表中有不同的重复元素)。