2015-01-29 11 views
12

W jednym z moich testów chcę mieć pewność, że kolekcja zawiera określone elementy. Dlatego chcę porównać tę kolekcję z przedmiotami oczekiwanej kolekcji , nie odnosząc się do kolejności pozycji. Obecnie mój kod testowy wygląda mniej więcej tak:Czy w Xunit.net można łatwo porównać dwie kolekcje bez uwzględniania kolejności przedmiotów?

[Fact] 
public void SomeTest() 
{ 
    // Do something in Arrange and Act phase to obtain a collection 
    List<int> actual = ... 

    // Now the important stuff in the Assert phase 
    var expected = new List<int> { 42, 87, 30 }; 
    Assert.Equal(expected.Count, actual.Count); 
    foreach (var item in actual) 
     Assert.True(expected.Contains(item)); 
} 

Czy jest jakiś łatwiejszy sposób osiągnięcia tego w Xunit.net? Nie mogę użyć Assert.Equal, ponieważ ta metoda sprawdza, czy kolejność pozycji jest taka sama w obu kolekcjach. Spojrzałem na Assert.Collection, ale to nie usuwa oświadczenie Assert.Equal(expected.Count, actual.Count) w powyższym kodzie.

Dzięki za odpowiedzi z góry.

Odpowiedz

14

Brad Wilson z xunit.net powiedział mi w tym, że trzeba Github Issue użyj operatora LINQ: OrderBy, a następnie Assert.Equal, aby sprawdzić, czy dwie kolekcje zawierają równe pozycje bez uwzględniania ich kolejności. Oczywiście, musiałbyś posiadać właściwość na odpowiedniej klasie przedmiotów, której możesz użyć do zamawiania w pierwszej kolejności (czego tak naprawdę nie miałem w moim przypadku).

Osobiście rozwiązałem ten problem, używając biblioteki FluentAssertions, która zapewnia wiele metod asercji, które można zastosować w płynnym stylu. Oczywiście, there are also a lot of methods that you can use to validate collections.

W kontekście moje pytanie, chciałbym użyć czegoś jak następujący kod:

[Fact] 
public void Foo() 
{ 
    var first = new[] { 1, 2, 3 }; 
    var second = new[] { 3, 2, 1 }; 

    first.Should().BeEquivalentTo(second); 
} 

Ten test przechodzi ponieważ wywołanie BeEquivalentTo ignoruje kolejność elementów.

Shouldly to również dobra alternatywa, jeśli nie chcesz korzystać z FluentAssertions.

7

Nie xUnit, ale LINQ odpowiedź:

bool areSame = !expected.Except(actual).Any() && expected.Count == actual.Count; 

Więc w xUnit:

Assert.True(!expected.Except(actual).Any() && expected.Count == actual.Count)); 

Jako @ Robi-y powiedział w Microsoft.VisualStudio.QualityTools.UnitTestFramework jest CollectionAssert.AreEquivalent

+0

Należy również sprawdzić rozmiary choć prawda? – aquinas

+1

Myślę, że masz rację: aaquinas: odpowiedź Rapha nie powiedzie się, jeśli lista 1 to {1, 3, 5}, a lista 2 to {1, 3, 3, 3, 5}. Teraz, gdy o tym myślę, sprawdzenie rozmiarów może nie wystarczyć, ponieważ byłoby to niemożliwe, jeśli lista 1 to {1, 1, 3, 5, 5}, a lista 2 to {1, 3, 3, 5, 5}.Nadal +1 do Raph za bardzo elegancki punkt wyjścia. –

+0

Z wyjątkiem różnic między dwiema listami. Jeśli na liście znajduje się więcej pozycji, ten przedmiot zostanie uzyskany. Nie ma potrzeby sprawdzania rozmiarów. – rducom

4

Może inny sposób jest:

Assert.True(expected.SequenceEqual(actual)); 

Sprawdza to również zamówienie. To co się dzieje wewnętrznie:

using (IEnumerator<TSource> e1 = first.GetEnumerator()) 
     using (IEnumerator<TSource> e2 = second.GetEnumerator()) 
     { 
      while (e1.MoveNext()) 
      { 
       if (!(e2.MoveNext() && comparer.Equals(e1.Current, e2.Current))) return false; 
      } 
      if (e2.MoveNext()) return false; 
     } 
     return true; 

Więc jeśli nie dbają o porządek, wystarczy zamówić obie listy przed

Assert.True(expected.OrderBy(i => i).SequenceEqual(actual.OrderBy(i => i))); 
+0

Dziękuję Raph - może powinienem był podać w mojej odpowiedzi, że rzeczywista lista niekoniecznie zawiera wartości int. W rzeczywistości wartości, których używam, nie mogą być uporządkowane (tj. Odpowiednie klasy nie implementują 'IComparable '). Zatem 'SequenceEqual' nie jest opcją, ponieważ sprawdza kolejność pozycji. – feO2x

+0

Jeśli masz własność tożsamości na swojej klasie, możesz jej użyć do zamówienia według tej właściwości. W najgorszym przypadku możesz zaimplementować niestandardową klasę IEqualityComparer . – rducom

0

Można użyć CollectionAssert.AreEquivalent od Microsoft

CollectionAssert.AreEquivalent(expected, actual);