Assit, Junit'teki 2 Liste'ye eşittir


165

JUnit test senaryosundaki listeler arasında nasıl bir eşitlik iddiası yapabilirim ? Eşitlik listenin içeriği arasında olmalıdır.

Örneğin:

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

5
assertArrayEqualsBugünlerde kullanmayı seviyorum . İle birlikte kullanın List#toArray.
Thibstars

@Thibstars - Bunu cevap olarak değerlendiririm.
dfrankow

2
assertArrayEqualslistelerinizden diziler almanızı gerektirir. Listeden doğrudan listeden çalıştırabilirsinizassertIterableEquals
ThetaSinner

assertIterableEqualsjUnit5 @ThetaSinner için kullanılabilir
iec2011007

Yanıtlar:


170

Bunun birkaç yıl önce sorulduğunu anlıyorum, muhtemelen bu özellik o zamanlar değildi. Ancak şimdi bunu yapmak kolaydır:

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

Junc'un hamcrest ile yüklenmiş yeni bir sürümüne sahipseniz, şu içe aktarmaları ekleyin:

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


3
System.out.println(actual == expected);false döndürür, ancak System.out.println(actual.equals(expected));true döndürür.
Yayın

@Catfish evet, bu kafa karıştırıcı değil mi. Bence eşleştiricinin.equals(..) bunun yerine== ?
djeikyb

2
Bu nasıl assertEquals daha iyi?
Raedwald

1
@ Onaylama başarısız olduğunda çıktıyı çıktılayın. fark düzenlemek için daha sonra geri gelmek çalışacağım. hamcrest eşleştiricileri ayrıntılı hata mesajları üretebilir. Junit'in iddiayı basitçe aşırı yüklemesi mümkündür. ama çoğunlukla junit çekirdek birim test özellikleri sağlar ve hamcrest güzel bir nesne farkı describer kütüphanesi sağlar.
djeikyb

29

Dizgiye dönüştürmeyin ve karşılaştırın. Bu performans için iyi değil. Junit'te Corematchers'ın içinde bunun için bir eşleşme var =>hasItems

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

Bu listedeki elemanları kontrol etmenin daha iyi bir yolu.


2
Tek bir notla seçilen cevap olmalı: Listede ne istediğinizin dışında başka öğe olmadığını da doğrulamanız gerekir. Belki kullanın:Assert.assertEquals(4,yourList.size());
yoni

ya da tek bir satırla:assertThat(yourList.toArray(), arrayContainingInAnyOrder(1,2,3,4,5));
user1778602

3
"Bu performans için iyi değil." Birim testleri yazarken performansın ne derece dikkate alınması gerektiğinden emin değilim ... Ancak, dizeleri toString()sürümleriyle karşılaştırmak en iyi yol değildir.
walen

21

Bu, JUnit 4.3 ve altı için uygun eski bir yanıttır. JUnit'in modern sürümü, assertThat yönteminde yerleşik okunabilir hata iletileri içerir. Mümkünse, bu soruya başka yanıtlar tercih edin.

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

Kayıt için, @Paul'un bu cevaba yaptığı yorumunda belirtildiği gibi, iki Lists eşittir:

yalnızca ve belirtilen nesne de bir liste ise, her iki liste de aynı boyuta sahiptir ve iki listedeki karşılık gelen tüm öğe çiftleri eşittir. (İki öğe e1ve e2eğer eşitse (e1==null ? e2==null : e1.equals(e2)).) Diğer bir deyişle, aynı liste aynı sırada yer alıyorsa, iki liste eşit olarak tanımlanır. Bu tanım, eşittir yönteminin Listarabirimin farklı uygulamalarında düzgün çalışmasını sağlar.

Bkz ait javadocs Listarayüzüne .


1
Yani beklenen.equals (a) listenin tuttuğu nesneleri iddia etmekle ilgilenecek mi?
Kamal

1
Listeden javadoc: Belirtilen nesneyi eşitlik için bu listeyle karşılaştırır. Yalnızca belirtilen nesne de bir listeyse, her iki liste de aynı boyuta sahipse ve iki listedeki karşılık gelen tüm öğe çiftleri eşitse true değerini döndürür. (E1 ve e2 öğelerinin iki değeri eşitse (e1 == null? E2 == null: e1.equals (e2)). Başka bir deyişle, aynı öğeyi aynı sırayla içeriyorlarsa iki liste eşit olarak tanımlanır . Bu tanım, eşitleme yönteminin Liste arabiriminin farklı uygulamalarında düzgün çalışmasını sağlar.
Paul McKenzie

1
Bu ne yazık ki yararlı hata mesajı daha az sağlar. Hangi öğeleri farklı görebilirsiniz böylece bir döngü gerçekleştiren bir yardımcı sınıf yazmak daha iyi bulduk.
Michael Lloyd Lee mlk

@mlk, belki de, ama böyle bir şey için özel bir yardımcı program yazmakta tereddüt ediyorum. Şimdi düzenlediğim hata mesajı ne olacak?
Bart Kiers

@mlk Her bir öğeyi test etmek için bir döngü yazmanın daha iyi olabileceğini kabul ediyorum; Listede ne tür nesnelerin bulunduğuna bağlıdır. Dizeler ise, yalnızca "a =" + a ifadesinin iyi olması gerektiğini söyleyin, ancak karmaşık nesneler (diğer listeler veya toString uygulaması iyi olmayan bir şey) ise, bunları tek tek test etmek daha kolay olabilir
Matt N

20

assertEquals(Object, Object)JUnit4 dan / JUnit 5 veya assertThat(actual, is(expected));hamcrest hem sadece çalışacak diğer yanıtlar önerilen equals()vetoString() kıyasla nesne sınıflarının (ve derin) için overrided edilir.

Önemdeki eşitlik testi equals()ve test başarısızlık mesajı toString()karşılaştırılan nesnelere dayandığı için önemlidir .
Gibi yerleşik sınıflar için String, Integervb. İçin sorun değil, çünkü bu ikisini de geçersiz kılar equals()ve toString(). Bu nedenle iddia etmek List<String>ya List<Integer>da iddia etmek için mükemmel bir şekilde geçerlidir assertEquals(Object,Object).
Ve bu konuda: equals()bir sınıfta geçersiz kılmalısınız çünkü nesne eşitliği açısından mantıklıdır, sadece JUnit ile yapılan bir testte iddiaları kolaylaştırmak için değil.
İddiaları kolaylaştırmak için başka yollarınız da var.
İyi bir uygulama olarak iddia / eşleştirme kütüphanelerini tercih ediyorum.

İşte bir AssertJ çözümü.

org.assertj.core.api.ListAssert.containsExactly() İhtiyacınız olan şey budur: javadoc'ta belirtildiği gibi, gerçek grubun tam olarak verilen değerleri ve başka hiçbir şey içermediğini doğrular.

Diyelim ki, Fooeleman eklediğiniz ve bunu alabileceğiniz bir sınıf.
Bu birim testi Foo, iki listenin aynı içeriğe sahip olabileceğini iddia eder:

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 iyi bir nokta, a'nın Listbeklendiği gibi bildirilmesinin gereksiz olmasıdır: bu, iddiayı daha da zorlaştırır ve kodu daha okunabilir kılar:

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

Ancak, iddia / eşleştirici kütüphaneleri bir zorunluluktur, çünkü bunlar gerçekten daha da ilerleyecektir.
Şimdi varsayalım s değil s örneklerini Foo saklayın . Bu çok yaygın bir ihtiyaç. AssertJ ile iddianın yazılması hala basittir. Daha iyisi, JUnit yolu aşağıdakileri gerektirirken öğelerin sınıfı geçersiz kılmasa bile liste içeriğinin eşit olduğunu iddia edebilirsiniz :StringBar
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

Elemanların sırasını umursamıyorsanız ListAssert.assertEquals, junit-eklentilerine tavsiye ederim .

Bağlantı: http://junit-addons.sourceforge.net/

Tembel Maven kullanıcıları için:

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

7
Not: Öğelerin sırasını umursamıyorsanız, Liste değil, bir Küme veya Koleksiyon kullanmalısınız.
Barett

11
Katılıyorum. Bu kütüphane brüttür. Neden yeryüzünde ListAssert.assertEquals () varsayılan olarak düzensiz?
Ryan

5

Junit içinde assertEquals kullanabilirsiniz .

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

Elemanların sırası farklıysa hata döndürür.

Bir model nesnesi listesi varsa, belirli bir modeldeki eşittir yöntemini geçersiz kılmalısınız.

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

4

bir dizi listesi oluşturmak istemiyorsanız, bunu da deneyebilirsiniz

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

1

Tekerleği yeniden icat etme!

Bunu sizin için yapan bir Google Code kütüphanesi var: Hamcrest

[Hamcrest] 'eşleşme' kurallarının bildirici olarak tanımlanmasına ve diğer çerçevelerde kullanılmasına izin veren eşleme nesneleri (kısıtlamalar veya tahminler olarak da bilinir) içeren bir kütüphane sağlar. Tipik senaryolar arasında test çerçeveleri, alay kütüphaneleri ve kullanıcı arayüzü doğrulama kuralları bulunur.


0

Bu sorunu çözmek için zaten birçok seçenek olduğunu biliyorum, ancak herhangi bir oder iki liste iddia etmek için aşağıdakileri tercih ederim :

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

Sipariş eşleşmezse bu başarısız olmaz mı ??
iec2011007

0

assertEquals(expected, result);benim için çalışıyor. Bu işlev iki nesne aldığından, ona herhangi bir şey iletebilirsiniz.

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

-1

Bunu yapmıyorum, yukarıdaki tüm cevaplar iki Nesne listesini karşılaştırmak için kesin çözüm veriyor. Yukarıdaki yaklaşımların çoğu yalnızca aşağıdaki karşılaştırma sınırında yardımcı olabilir - Boyut karşılaştırması - Referans karşılaştırması

Ancak aynı büyüklükte nesne listelerimiz ve nesne düzeyindeki farklı verilerimiz varsa, bu karşılaştırma yaklaşımları yardımcı olmaz.

Aşağıdaki yaklaşım, kullanıcı tanımlı nesne üzerinde eşittir ve hashcode yöntemi geçersiz kılmak ile mükemmel çalışacağını düşünüyorum.

Eşit değerleri ve hashcode'u geçersiz kılmak için Xstream lib'i kullandım, ancak kazanılan mantık / karşılaştırma ile eşitleri ve hashcode'u geçersiz kılabiliriz.

İşte referans için örnek

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

En önemli şey, Nesnelerin eşit kontrolüne herhangi bir alan eklemek istemiyorsanız alanları Ek Açıklama (@XStreamOmitField) ile yok sayabilirsiniz. Yapılandırmak için bunun gibi birçok Ek Açıklama vardır, bu yüzden bu lib'in ek açıklamalarına derinlemesine bakın.

Eminim bu cevap iki nesne listesini karşılaştırmak için doğru yaklaşımı belirlemek için zaman kazandıracaktır :). Bu konuda herhangi bir sorun görürseniz lütfen yorum yapın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.