assert在junit中的两个列表之间等于

flseospp  于 2021-06-29  发布在  Java
关注(0)|答案(14)|浏览(699)

如何在junit测试用例中的列表之间进行相等Assert?列表内容之间应该相等。
例如:

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

// numbers should be equal to numbers2
//numbers should not be equal to numbers3
qjp7pelc

qjp7pelc1#

assertEquals(Object, Object) 来自junit4/JUnit5或 assertThat(actual, is(expected)); 从汉克雷斯特提出的其他答案只能作为两者 equals() 以及 toString() 为比较对象的类(和深度)重写。
这很重要,因为Assert中的相等性测试依赖于 equals() 测试失败消息依赖于 toString() 比较对象的。
对于内置类,例如 String , Integer 所以。。。没问题,因为这两个都会覆盖 equals() 以及 toString() . 所以Assert是完全正确的 List<String> 或者 List<Integer>assertEquals(Object,Object) .
关于这件事:你必须推翻 equals() 因为它在对象相等性方面是有意义的,而不仅仅是在junit测试中使Assert更容易。
为了使Assert更容易,你有其他的方法。
作为一个好的实践,我倾向于Assert/匹配器库。
这里有一个assertj解决方案。 org.assertj.core.api.ListAssert.containsExactly() 是您所需要的:它验证实际组是否完全包含给定的值,而不包含任何其他内容,顺序如javadoc中所述。
假设一个 Foo 类在何处添加元素以及在何处可以获得这些元素。
单元测试 Foo Assert这两个列表具有相同的内容可能如下所示:

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");
}

资产的一个优点是 List 正如预期的那样是不必要的:它使Assert更直接,代码更可读:

Assertions.assertThat(foo.getElements())
         .containsExactly("One", "Two", "Three");

但是Assert/匹配器库是必须的,因为它们将真正进一步。
现在假设 Foo 不存储 String 但是 Bar 的示例。
这是一个非常普遍的需要。使用assertj,Assert仍然很容易编写。更好的是,即使元素的类没有重写,也可以Assert列表内容是相等的 equals()/hashCode() junit way要求:

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"));
}
bn31dyow

bn31dyow2#

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

@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  
}
rnmwe5a2

rnmwe5a23#

不要转换为字符串并进行比较。这不利于表现。在junit中,corematchers内部有一个匹配器 hasItems ```
List yourList = Arrays.asList(1,2,3,4)
assertThat(yourList, CoreMatchers.hasItems(1,2,3,4,5));

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

kxeu7u2r4#

这是一个遗留的答案,适用于JUnit4.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在对这个答案的评论中提到的,两个 List s等于:
当且仅当指定的对象也是一个列表时,两个列表具有相同的大小,并且两个列表中所有对应的元素对都相等(两个要素 e1 以及 e2 如果 (e1==null ? e2==null : e1.equals(e2)) 换句话说,如果两个列表包含相同顺序的相同元素,则它们被定义为相等。此定义确保equals方法在 List 接口。
请参阅 List 接口。

6tdlim6h

6tdlim6h5#

您可以在junit中使用assertequals。

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);
    }

如果元素的顺序不同,则返回错误。
如果您正在Assert一个模型对象列表,那么您应该重写特定模型中的equals方法。

@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;
    }
nkkqxpd9

nkkqxpd96#

我知道已经有很多方法可以解决这个问题,但我更愿意按以下步骤在任何顺序Assert两个列表:

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

2cmtqfgy7#

如果你不关心元素的顺序,我建议 ListAssert.assertEquals 在junit插件中。
链接:http://junit-addons.sourceforge.net/
对于懒惰的maven用户:

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

5anewei68#

assertEquals(expected, result); 对我有用。因为这个函数有两个对象,所以可以传递任何东西给它。

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

5m1hhzi49#

为了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)));
}

如果您在hamcrest中安装了junit的最新版本,只需添加以下导入:

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

http://junit.org/junit4/javadoc/latest/org/junit/assert.html#assertthat(t,org.hamcrest.matcher)
http://junit.org/junit4/javadoc/latest/org/hamcrest/corematchers.html
http://junit.org/junit4/javadoc/latest/org/hamcrest/core/is.html

ej83mcc0

ej83mcc010#

我不知道以上所有的答案都给出了比较两个对象列表的精确解。上述大多数方法都有助于遵循比较的极限-规模比较-参考比较
但是,如果我们有相同大小的对象列表和对象级别上不同的数据,那么这种比较方法就没有帮助了。
我认为下面的方法可以很好地在用户定义的对象上重写equals和hashcode方法。
我使用xstream lib重写equals和hashcode,但是我们也可以通过out-won逻辑/比较来重写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);
      }
    }

最重要的是,如果不想在对象的相等检查中包含任何字段,则可以通过注解忽略字段(@xstreamitfield)。有许多这样的注解需要配置,所以请深入了解这个库的注解。
我相信这个答案将节省您确定比较两个对象列表的正确方法的时间:)。请评论,如果你看到这方面的任何问题。

w8ntj3qf

w8ntj3qf11#

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

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

assertTrue(figureTypes .equals(figureTypes2 ));
vngu2lb8

vngu2lb812#

对于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());
bfhwhh0e

bfhwhh0e13#

不要重新发明轮子!
有一个google代码库可以帮你做到这一点:hamcrest
[hamcrest]提供了一个matcher对象库(也称为约束或 predicate ),允许以声明方式定义“match”规则,以便在其他框架中使用。典型的场景包括测试框架、模拟库和ui验证规则。

mzsu5hc0

mzsu5hc014#

您提到您对列表内容的平等性感兴趣(没有提到顺序)。所以呢 containsExactlyInAnyOrder 来自assertj的很适合。它的 Package 是 spring-boot-starter-test ,例如。
从assertj docs listsassert#containseactlyinyorder:
验证实际组是否完全包含给定的值,而不包含其他任何顺序的值。例子:

// 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);

相关问题