JUnit 4 porównaj zestawy

102

Jak zwięźle zapewniłbyś równość Collectionelementów, a konkretnie Setw JUnit 4?

Eqbal
źródło
2
sprawdź ten wpis SO stackoverflow.com/questions/1086691/collectionassert-in-junit
Teja Kantamneni
Czy próbujesz stwierdzić, że dwa zestawy są sobie równe (zawierają te same elementy), czy też dwa elementy tego samego zestawu są równe?
Bill the Lizard
Muszę zobaczyć, że elementy dwóch setów są równe
Eqbal

Odpowiedzi:

103

Możesz stwierdzić, że te dwa Sets są sobie równe, co wywołuje Set equals()metodę .

public class SimpleTest {

    private Set<String> setA;
    private Set<String> setB;

    @Before
    public void setUp() {
        setA = new HashSet<String>();
        setA.add("Testing...");
        setB = new HashSet<String>();
        setB.add("Testing...");
    }

    @Test
    public void testEqualSets() {
        assertEquals( setA, setB );
    }
}

To @Testprzejdzie, jeśli dwa Sets mają ten sam rozmiar i zawierają te same elementy.

Bill the Lizard
źródło
7
Nie daje to bardzo dobrych wyników w raporcie. Jeśli twoje toStrings są jasno zdefiniowane, jest lepsze, ale nadal nie jest dobre (niewielka różnica może skończyć się stroną z tekstem)
Bill K
Uhm, jak to się stało: java.lang.AssertionError: spodziewany: java.util.Hashtable <{CompanyName = 8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric = sZwmXAdYKv, Category = AvrIfd, QuoteameId = 43426va wass: {0247} ja: 22426 = 8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric = sZwmXAdYKv, Category = AvrIfd, QuoteId = 4342740204922826921}>
Giovanni Botta
3
@Giodude Czy masz equalsi hashCodezaimplementowałeś w klasie, którą przechowujesz w Hashtable?
Bill the Lizard
Jak widać, to tylko ciągi znaków i długie ... Testuję Avro, aby serializować i deserializować mapę i to jest wynik. Myślę, że musi być coś podejrzanego w sposobie, w jaki ciągi są serializowane i deserializowane, co powoduje niepowodzenie testu, ale nie mogę znaleźć problemu.
Giovanni Botta
Nie działa dla mnie, mimo że porównuję dwa HashSet <Long>. Odpowiedź @MattFriedman faktycznie działa w moim przypadku użycia.
bluecollarcoder
46

Apache commons znowu na ratunek.

assertTrue(CollectionUtils.isEqualCollection(coll1, coll2));

Działa jak marzenie. Nie wiem dlaczego, ale stwierdziłem, że w przypadku kolekcji poniższe assertEquals(coll1, coll2)nie zawsze działają. Na wypadek, gdyby mi się nie udało, miałem dwie kolekcje wspierane przez zestawy. Ani hamcrest, ani junit nie powiedzieliby, że kolekcje są równe, chociaż wiedziałem na pewno, że tak. Korzystanie z CollectionUtils działa doskonale.

Matt Friedman
źródło
20
To jest właściwie trywialne, trudna część polega na tym, aby wyraźnie wskazać różnicę dzwoniącemu
Bill K
1
Zaakceptowana odpowiedź jest dobrą odpowiedzią na pierwotne pytanie (test jednostkowy konkretnie dla dwóch zestawów), ale ta odpowiedź z CollectionUtils jest moim zdaniem lepszą odpowiedzią w najbardziej ogólnym przypadku. Nie mogłem porównać kolekcji i zestawu bez użycia CollectionUtils.
Jay
16

z hamakiem :

assertThat(s1, is(s2));

z prostym stwierdzeniem:

assertEquals(s1, s2);

NB: t używana jest metoda equals () klasy zbioru konkretów

dfa
źródło
1
Wolę tę metodę, ponieważ Hamcrest jest dostarczany z JUnit 4, więc nie są potrzebne inne biblioteki.
JRSofty
2
Może to nie działać, gdy zestawy mają różne typy.
Hans-Peter Störr
7

Szczególnie interesujący jest przypadek porównania

   java.util.Arrays$ArrayList<[[name,value,type], [name1,value1,type1]]> 

i

   java.util.Collections$UnmodifiableCollection<[[name,value,type], [name1,value1,type1]]>

Jak dotąd jedynym rozwiązaniem, które widzę, jest zamiana obu w zestawy

assertEquals(new HashSet<CustomAttribute>(customAttributes), new HashSet<CustomAttribute>(result.getCustomAttributes()));

Albo mógłbym porównać je element po elemencie.


źródło
W rzeczywistości istnieje kilka rozwiązań przedstawionych w innych odpowiedziach. Zestawy i tak są trochę niefortunne, ponieważ ignorują zamówienie. Może ArrayList?
Hans-Peter Störr
4

Jako dodatkową metodę opartą na tablicy ... możesz rozważyć użycie nieuporządkowanych asercji tablicowych w junitx. Chociaż przykład Apache CollectionUtils będzie działał, jest tam również pakiet solidnych rozszerzeń asercji:

Myślę że

ArrayAssert.assertEquivalenceArrays(new Integer[]{1,2,3}, new Integer[]{1,3,2});

podejście będzie znacznie bardziej czytelne i możliwe do debugowania (wszystkie kolekcje obsługują toArray (), więc użycie metod ArrayAssert powinno być dość łatwe.

Oczywiście wadą jest to, że junitx jest dodatkowym plikiem jar lub wpisem maven ...

 <dependency org="junit-addons" name="junit-addons" rev="1.4"/>
jayunit100
źródło
2

Sprawdź ten artykuł . Oto jeden przykład:

@Test  
public void listEquality() {  
    List<Integer> expected = new ArrayList<Integer>();  
    expected.add(5);  

    List<Integer> actual = new ArrayList<Integer>();  
    actual.add(5);  

    assertEquals(expected, actual);  
}  
rzymski
źródło
krótki, ale świetny Link, wyjaśnia bardzo szybko, co możesz zrobić z Junit4-
Johannes
1
Link jest uszkodzony. Czy jest szansa, że ​​znajdziesz zarchiwizowaną wersję online lub podsumujesz jej zawartość?
pzp
1

Korzystanie z Hamcrest:

assertThat( set1, both(everyItem(isIn(set2))).and(containsInAnyOrder(set1)));

Działa to również wtedy, gdy zestawy mają różne typy danych i zgłaszają różnicę, a nie tylko błąd.

Hans-Peter Störr
źródło
2
Jaki jest import isIn? IntelliJ nie może rozwiązać importu z żadnym pakietem hamcret.
fabien
0

Jeśli chcesz sprawdzić, czy lista lub zestaw zawiera zestaw określonych wartości (zamiast porównywać je z już istniejącą kolekcją), często przydaje się metoda kolekcji toString:

String[] actualResult = calltestedmethod();
assertEquals("[foo, bar]", Arrays.asList(actualResult).toString());

List otherResult = callothertestedmethod();
assertEquals("[42, mice]", otherResult.toString());

Jest to trochę krótsze niż pierwsze skonstruowanie oczekiwanej kolekcji i porównanie jej z rzeczywistą kolekcją oraz łatwiejsze do napisania i poprawienia.

(Wprawdzie nie jest to szczególnie czysta metoda i nie jest w stanie odróżnić elementu „foo, bar” od dwóch elementów „foo” i „bar”. Ale w praktyce myślę, że najważniejsze jest to, że pisanie testów jest łatwe i szybkie , w przeciwnym razie wielu programistów po prostu tego nie zrobi bez naciskania.)

Hans-Peter Störr
źródło
To sprawia, że ​​wynik testu jednostkowego zależy od implementacji toString from list. Jeśli zdecydują się zmienić formatowanie, test jednostkowy przestanie działać. Nie uważałbym tego za bezpieczne.
Laurens Op 't Zandt
@ LaurensOp'tZandt Masz na myśli zmianę formatu Collection.toList () przez Oracle? To z pewnością się nie wydarzy. Masz jednak rację, że nie jest to szczególnie czyste. Ale w praktyce mam wrażenie, że najważniejsze jest to, że bardzo łatwo jest pisać testy.
Hans-Peter Störr
Zgadzam się, myślę, że metoda toString raczej nie będzie przypadkowa. Więc prawdopodobnie będzie dalej działać. Chciałem tylko zaznaczyć, że nie jest to bardzo czysty sposób. Ale rzeczywiście jest to bardzo łatwe. Jednym z problemów, który się pojawia, jest porównywanie zbiorów. Ponieważ ich kolejność nie jest gwarantowana.
Laurens Op 't Zandt
0

Podoba mi się rozwiązanie Hansa-Petera Störra ... Ale myślę, że nie jest do końca poprawne. Niestety containsInAnyOrdernie akceptuje Collectionżadnych obiektów do porównania. Musi więc być a Collectionz Matchers:

assertThat(set1, containsInAnyOrder(set2.stream().map(IsEqual::equalTo).collect(toList())))

Import to:

import static java.util.stream.Collectors.toList;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
FLUXparticle
źródło