2012-05-24 16 views
14

Mam klasę PagedModel, która implementuje IEnumerable, aby po prostu zwrócić dane modelu, ignorując dane stronicowania. Nadpisałem także wartości równe i kod GetHashCode, aby umożliwić porównywanie dwóch obiektów PagedModel za pomocą ich wartości ModelData, PageNumber i TotalPages oraz PageSize.Assert.AreEqual nie używa moich nadpisań .Equals na implementacji IEnumerable

tutaj jest problem

Dim p1 As New PagedModel() With { 
    .PageNumber = 1, 
    .PageSize = 10, 
    .TotalPages = 10, 
    .ModelData = GetModelData() 
} 

Dim p2 As New PagedModel() With { 
    .PageNumber = 1, 
    .PageSize = 10, 
    .TotalPages = 10, 
    .ModelData = GetModelData() 
} 

p1.Equals(p2) =====> True 
Assert.AreEqual(p1, p2) ======> False! 

to wygląda NUnit dzwoni to wewnętrzna metoda EnumerableEqual porównać mój PagedModel, zamiast przy użyciu Równa metod przewidzianych ja! Czy istnieje sposób na zastąpienie tego zachowania lub czy muszę napisać niestandardowe asercje.

Odpowiedz

9

Robi co prosicie: Radziłbym przeciwko nim, ale jeśli naprawdę nie podoba zachowanie NUnit i chcą dostosować twierdzenie można dostarczyć własne EqualityComparer.

Assert.That(p1, Is.EqualTo(p2).Using(myCustomEqualityComparer)); 

Co należy robić (krótka odpowiedź): Trzeba GetHashCode i równa na ModelData zamiast PagedModel ponieważ używasz PagedModel jak gromadzenie i ModelData jako elementów.

Co należy robić (Long) odpowiedź: Zamiast nadrzędnymi Equals(object) na PagedModel trzeba zaimplementować IEquatable<T> na ModelData, gdzie T jest parametrem typu do IEnumerable, jak również ręcznego GetHashCode(). Te dwie metody są tym, czego wszystkie metody IEnumerable w .Net używają do określenia równości (dla operacji takich jak Union, Distinct itp.) Podczas korzystania z Default Equality Comparer (nie określasz własnego IEqualityComparer).

[Domyślne równości porĂłwnywarka] sprawdza, czy typ T implementuje System.IEquatable interfejs, a jeśli tak, to zwraca EqualityComparer korzystające z tego wykonania. W przeciwnym razie, zwraca EqualityComparer że używa przesłonięcia z Object.Equals i Object.GetHashCode dostarczone przez T.


Aby działać poprawnie, GetHashCode musi powrócić takie same rezultaty dla wszystkich obiektów, które zwracają prawdziwe dla .equals (T). Odwrotna sytuacja niekoniecznie musi być prawdziwa - GetHashCode może zwracać kolizje dla obiektów, które nie są równe. More information here - see Marc Gravel's accepted answer. Również znalazłem wdrożenie GetHashCode w tej odpowiedzi przy użyciu liczb pierwszych bardzo przydatne.

+0

Ta odpowiedź brzmi, że zasadniczo w implementacji należy jawnie zaimplementować IEquatable .Equals ... zobacz http://stackoverflow.com/questions/1577149/explicit-interface-implementation-in-vb-net – Jay

+0

Nie, wdrożenie IEquatable nie wystarczy. Implementacja GetHashCode jest równie ważna. Ważne jest również zrozumienie, że IEnumerable nie jest w stanie używać Equals (obiektu), jeśli nie zaimplementujesz IEquatable (patrz cytat w moim poście), więc nie jest to absolutnie wymagane. – csauve

+0

Powiedziałem, że implementuję program IEquatable.Equals, który nie powinien zezwalać na domyślny powrót, ponieważ metoda byłaby przesłonięciem, a implementacja jawnie wywoływałaby tę metodę ... – Jay

1

Jeśli przyjrzeć się realizacji comparer równości NUnit w GIT repo, widać, że nie jest dedykowany blok porównanie dwóch wyliczeń, który ma wyższy priorytet (tylko dlatego, że jest umieszczony wyżej) niż comparisons przy użyciu interfejsu IEquatable<T> lub metody Object.Equals(Object), które zostały zaimplementowane lub przeciążone w klasie PagedModel.

ja nie wiem, czy jest to błąd lub funkcja, ale chyba powinien zadać sobie najpierw, czy wdrożenie interfejsu IEnumerable<ModelData> bezpośrednio klasie PagedModel jest rzeczywiście najlepszym rozwiązaniem, zwłaszcza dlatego, że PagedModel jest czymś więcej niż tylko wyliczenie instancji ModelData.

Prawdopodobnie wystarczy (lub nawet lepiej) podać wyliczenie ModelData za pośrednictwem prostej, tylko do odczytu, klasy klasy PagedModel. NUnit przestałby patrzeć na twój obiekt PagedModel jak na proste wyliczenie obiektów, a twoje testy jednostkowe zachowałyby się zgodnie z oczekiwaniami.

Jedyną inną opcją jest ta sugerowana przez csauve; zaimplementować prosty zwyczaj IComparer dla PagedModel i dostarczyć instancję go wszystkim twierdzi, gdzie można porównać dwa PagedModel instancje:

internal class PagedModelComparer : System.Collections.IComparer 
{ 
    public static readonly IComparer Instance = new PagedModelComparer(); 

    private PagedModelComparer() 
    { 
    } 

    public int Compare(object x, object y) 
    { 
     return x is PagedModel && ((PagedModel)x).Equals(y); 
    } 
} 

    ... 
    [Test] 
    ... 
     Assert.That(actual, Is.EqualTo(expected).Using(PagedModelComparer.Instance)); 
    ... 

Ale to sprawi, że testy bardziej skomplikowana, niż to konieczne i zawsze będziesz mieć do pomyśl o użyciu specjalnego porównywalnika podczas pisania dodatkowych testów dla urządzenia PagedModel.

Powiązane problemy