web-dev-qa-db-ja.com

Junitのリストについてアサートする

JUnitテストケースのリストについてアサーションを作成する方法は?リストのサイズだけでなく、リストの内容も。

139
Kamal

私はこれが数年前に尋ねられたことを知っています、おそらくこの機能は当時ではなかったでしょう。しかし、今では、これを行うのは簡単です:

@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

143
djeikyb

文字列に変換して比較しないでください。これはパフォーマンスには良くありません。 junitでは、Corematchers内に、このためのマッチャーがあります=> hasItems

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

これは、リスト内の要素をチェックするために知っているより良い方法です。

25
Andre Fonseca

これは、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がこの回答に対するコメントで述べたように、2つのListsは等しい:

指定されたオブジェクトもリストである場合にのみ、両方のリストのサイズは同じであり、2つのリストの対応する要素のペアはすべて等しい。 (2つの要素e1e2は、(e1==null ? e2==null : e1.equals(e2))の場合に等しい。)つまり、2つのリストは、同じ要素が同じ順序で含まれている場合に等しいと定義されます。この定義により、Listインターフェイスのさまざまな実装でequalsメソッドが適切に機能することが保証されます。

ListインターフェイスのJavaDocs を参照してください。

19
Bart Kiers

要素の順序を気にしない場合は、junit-addonsのListAssert.assertEqualsをお勧めします。

リンク: http://junit-addons.sourceforge.net/

怠zyなMavenユーザーの場合:

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

JUnit4/JUnit 5のassertEquals(Object, Object)または他の回答で提案されたHamcrestのassertThat(actual, is(expected));は、比較されるオブジェクトのクラス(および深く)でequals()toString()の両方がオーバーライドされる場合にのみ機能します。

アサーションの等価性テストはequals()に依存し、テスト失敗メッセージは比較されるオブジェクトのtoString()に依存するため、重要です。
Stringname __、Integername__などの組み込みクラスの場合...これらはequals()toString()の両方をオーバーライドするため、問題ありません。したがって、assertEquals(Object,Object)List<String>またはList<Integer>をアサートすることは完全に有効です。
そしてこの問題について:クラスでequals()をオーバーライドする必要があります。これは、JUnitを使用したテストでアサーションを簡単にするだけでなく、オブジェクトの同等性の観点からも意味があるからです。
アサーションを簡単にするために、他の方法があります。
グッドプラクティスとして、アサーション/マッチャーライブラリを優先します。

AssertJ ソリューションです。

org.assertj.core.api.ListAssert.containsExactly() は必要なものです。javadocに記載されている順序で、実際のグループに指定された値が正確に含まれていることを確認します。

要素を追加し、それを取得できるFooname__クラスを想定します。
2つのリストの内容が同じであることを主張するFooname__の単体テストは次のようになります。

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の良い点は、期待どおりにListname__を宣言する必要がないことです。これにより、アサーションがよりストレートになり、コードが読みやすくなります。

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

ただし、アサーション/マッチャーライブラリは必須です。
Fooname__がStringname__sではなく、Barname__sのインスタンスを格納するとします。
それは非常に一般的なニーズです。 AssertJを使用しても、アサーションの記述は簡単です。 JUnitの方法で必要な場合、要素のクラスがequals()/hashCode()をオーバーライドしない場合でも、リストの内容が等しいと断言できます。

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

配列リストを作成したくない場合は、これも試すことができます

@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  
}
3
List<Integer> figureTypes = new ArrayList<Integer>(
                           Arrays.asList(
                                 1,
                                 2
                            ));

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

assertTrue(figureTypes .equals(figureTypes2 ));
3

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

要素の順序が異なる場合、エラーが返されます。

モデルオブジェクトリストをアサートしている場合は、特定のモデルの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;
    }
2
Dhyan Mohandas

車輪を再発明しないでください!

これを行うGoogle Codeライブラリがあります: Hamcrest

[Hamcrest]マッチャーオブジェクト(制約または述語とも呼ばれる)のライブラリを提供し、「一致」ルールを宣言的に定義して、他のフレームワークで使用できるようにします。典型的なシナリオには、テストフレームワーク、モックライブラリ、およびUI検証ルールが含まれます。

1
Bohemian

上記のすべての答えが、オブジェクトの2つのリストを比較するための正確なソリューションを提供しているわけではありません。上記のアプローチのほとんどは、比較の制限のみに従う場合に役立ちます-サイズ比較-参照比較

ただし、同じサイズのオブジェクトのリストとオブジェクトレベルの異なるデータがある場合、この比較アプローチは役に立ちません。

次のアプローチは、ユーザー定義オブジェクトのequalsおよびhashcodeメソッドのオーバーライドで完全に機能すると思います。

Xstream libを使用して、equalsおよびhashcodeをオーバーライドしましたが、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);
      }
    }

最も重要なことは、オブジェクトの同等チェックにフィールドを含めたくない場合は、アノテーション(@XStreamOmitField)によってフィールドを無視できることです。設定するこのような多くの注釈がありますので、このライブラリの注釈について詳しく見てください。

この回答により、オブジェクトの2つのリストを比較するための正しいアプローチを特定する時間を節約できると確信しています。これに関する問題を見つけたらコメントしてください。

0