Uważam, że to powinno być naprawdę proste pytanie. Ale jakoś nie mogę znaleźć odpowiedzi w Google.
Załóżmy, że mam 2 listy ciągów. Pierwsza zawiera „Ciąg A” i „Ciąg B” , a druga zawiera „Ciąg B” i „Ciąg A” (zauważ różnicę w kolejności). Chcę je przetestować za pomocą JUnit, aby sprawdzić, czy zawierają dokładnie te same ciągi.
Czy istnieje potwierdzenie, które sprawdza równość ciągów znaków, które ignorują kolejność? Na przykład org.junit.Assert.assertEquals zgłasza AssertionError
java.lang.AssertionError: expected:<[String A, String B]> but was:<[String B, String A]>
Rozwiązaniem jest najpierw posortowanie list, a następnie przekazanie ich do asercji. Ale chcę, aby mój kod był tak prosty i czysty, jak to tylko możliwe.
Używam Hamcrest 1.3 , JUnit 4.11 , Mockito 1.9.5 .
list1.removeAll(list2)
powinien pozostaćlist1
pusty. Myślę, że możesz zbudować na tym, aby uzyskać to, czego chcesz.containsAll
iremoveAll
sąO(n²)
dla list podczas ich sortowania, a test równości jestO(nlogn)
.Collections.sort(list1); Collections.sort(list2); assertTrue(list1.equals(list2));
jest również czysty.Odpowiedzi:
Jak wspomniałeś, że używasz Hamcrest, wybrałbym jedną z kolekcji Matchers
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.junit.Assert.assertThat; public class CompareListTest { @Test public void compareList() { List<String> expected = Arrays.asList("String A", "String B"); List<String> actual = Arrays.asList("String B", "String A"); assertThat("List equality without order", actual, containsInAnyOrder(expected.toArray())); } }
źródło
Możesz użyć List.containsAll z assertTrue JUnit, aby sprawdzić, czy pierwsza lista zawiera każdy element z drugiego i odwrotnie.
źródło
assertEquals(first.size(), second.size())
.. może obejmować .. wtedy powinno działać zgodnie z oczekiwaniamiList<String> list1 = Arrays.asList("a", "a", "b");
List<String> list2 = Arrays.asList("a", "b", "b");
assertEquals(list1.size(), list2.size());
assertTrue(list1.containsAll(list2) && list2.containsAll(list1));
tym przykładzie oba potwierdzenia nie wykrywają, że listy są w rzeczywistości różne. @AlexWorden wspomina o CollectionUtils.isEqualCollection () z Apache Commons Collections, która w tym przykładzie poprawnie wykrywa, że kolekcje nie są równe.Oto rozwiązanie, które pozwala uniknąć złożoności kwadratowej (wielokrotne iterowanie po listach). Wykorzystuje klasę Apache Commons CollectionUtils do tworzenia mapy każdego elementu do liczby częstotliwości na liście. Następnie po prostu porównuje dwie mapy.
Assert.assertEquals("Verify same metrics series", CollectionUtils.getCardinalityMap(expectedSeriesList), CollectionUtils.getCardinalityMap(actualSeriesList));
Właśnie zauważyłem także CollectionUtils.isEqualCollection, która twierdzi, że robi dokładnie to, o co tutaj proszono ...
https://commons.apache.org/proper/commons-collections/apidocs/index.html?org/apache/commons/collections4/CollectionUtils.html
źródło
Z AssertJ,
containsExactlyInAnyOrder()
czylicontainsExactlyInAnyOrderElementsOf()
to, czego potrzebujesz:import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.List; public class CompareListTest { @Test public void compareListWithTwoVariables() { List<String> expected = Arrays.asList("String A", "String B"); List<String> actual = Arrays.asList("String B", "String A"); Assertions.assertThat(actual) .containsExactlyInAnyOrderElementsOf(expected); } @Test public void compareListWithInlineExpectedValues() { List<String> actual = Arrays.asList("String B", "String A"); Assertions.assertThat(actual) .containsExactlyInAnyOrder("String A", "String B"); } }
źródło
źródło
Spóźniłem się na imprezę, ale oto moje rozwiązanie wykorzystujące tylko Junit. Wszelkie myśli są mile widziane.
List<String> actual = new ArrayList<>(); actual.add("A"); actual.add("A"); actual.add("B"); List<String> expected = new ArrayList<>(); actual.add("A"); actual.add("B"); actual.add("B"); //Step 1: assert for size assertEquals(actual.size(), expected.size()); //Step 2: Iterate for(String e: expected){ assertTrue(actual.contains(e)); actual.remove(e); }
źródło
Zauważ, że rozwiązanie Roberta Izquierdo ma ogólnie złożoność kwadratową. Rozwiązanie w HashSets zawsze ma złożoność liniową:
assertTrue(first.size() == second.size() && new HashSet(first).equals(new HashSet(second)));
źródło
("s1", "s2", "s3" ,"s1")
a druga to,("s2", "s1", "s3" ,"s2");
nie są tą samą listą.Aby szybko naprawić, sprawdziłbym oba sposoby:
I próbując z sytuacją, w której liczba tych samych elementów jest różna (np. 1, 1, 2 i 1, 2, 2) nie otrzymałem fałszywych alarmów.
źródło
Możesz użyć ListAssert, który znajduje się w słoiku junit -addons.
ListAssert.assertEquals(yourList, Arrays.asList(3, 4, 5));
źródło
Wygląda na to, że inne odpowiedzi odnoszą się do narzędzi innych firm, są nieprawidłowe lub nieefektywne.
Oto rozwiązanie waniliowe O (N) w Javie 8.
public static void assertContainsSame(Collection<?> expected, Collection<?> actual) { assert expected.size() == actual.size(); Map<Object, Long> counts = expected.stream() .collect(Collectors.groupingBy( item -> item, Collectors.counting())); for (Object item : actual) assert counts.merge(item, -1L, Long::sum) != -1L; }
źródło