2012-05-24 21 views
14

Tôi có một lớp PagedModel mà thực hiện IEnumerable để chỉ trả về ModelData, bỏ qua dữ liệu phân trang. Tôi cũng đã ghi đè Equals và GetHashCode để cho phép so sánh hai đối tượng PagedModel với ModelData, PageNumber và TotalPages và PageSize của chúng.Assert.AreEqual không sử dụng .Equals của tôi ghi đè trên một thực hiện IEnumerable

Đây là vấn đề

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! 

Dường như NUnit đang kêu gọi đó là phương pháp EnumerableEqual nội bộ để so sánh PagedModel tôi thay vì sử dụng các phương pháp Equals tôi cung cấp! Có cách nào để ghi đè hành vi này không hay tôi phải viết một Assertion tùy chỉnh.

Trả lời

9

Làm những gì bạn đang yêu cầu: Tôi khuyên bạn nên chống lại nó nhưng nếu bạn thực sự không thích hành vi của NUnit và muốn tùy chỉnh xác nhận, bạn có thể cung cấp EqualityComparer của riêng bạn.

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

Những gì bạn nên làm (câu trả lời ngắn): Bạn cần GetHashCode và tương đương trên ModelData thay vì PagedModel kể từ khi bạn đang sử dụng PagedModel như bộ sưu tập và ModelData như các yếu tố.

Những gì bạn nên làm (Long trả lời): Thay vì trọng Equals(object) trên PagedModel bạn cần phải thực hiện IEquatable<T> trên ModelData, trong đó T là kiểu tham số cho IEnumerable, cũng như ghi đè GetHashCode(). Hai phương thức này là tất cả các phương thức IEnumerable trong .Net sử dụng để xác định sự bình đẳng (đối với các hoạt động như Union, Distinct etc) khi sử dụng Default Equality Comparer (bạn không chỉ định riêng IEqualityComparer).

Các [Mặc định Bình đẳng Comparer] kiểm tra xem loại T thực hiện các giao diện System.IEquatable và nếu như vậy, trả về một EqualityComparer sử dụng mà thực hiện. Nếu không, nó sẽ trả về một EqualityComparer mà sử dụng ghi đè của Object.equals và Object.GetHashCode cung cấp bởi T.


Để hoạt động tốt, GetHashCode cần phải trả lại kết quả tương tự cho tất cả các đối tượng quay trở lại đúng với Equals (T). Điều ngược lại không nhất thiết phải đúng - GetHashCode có thể trả về va chạm cho các đối tượng không bằng nhau. More information here - see Marc Gravel's accepted answer. Tôi cũng đã tìm thấy việc thực hiện GetHashCode trong câu trả lời đó bằng cách sử dụng số nguyên tố rất hữu ích.

+0

Câu trả lời này là gì về cơ bản trong triển khai của bạn, bạn cần triển khai rõ ràng IEquatable .Equals ... xem http://stackoverflow.com/questions/1577149/explicit-interface-implementation-in-vb-net – Jay

+0

Không, việc triển khai IEquatable là không đủ. Việc thực hiện GetHashCode cũng quan trọng. Nó cũng quan trọng để hiểu rằng IEnumerable rơi trở lại để sử dụng bằng (đối tượng) nếu bạn không thực hiện IEquatable (xem báo giá trong bài của tôi), do đó, làm như vậy là không hoàn toàn cần thiết. – csauve

+0

Tôi đã nói rõ ràng việc triển khai IEquatable.Equals không nên cho phép dự phòng mặc định vì phương thức sẽ ghi đè và việc triển khai rõ ràng sẽ gọi cho phương thức đã nói ... – Jay

1

Nếu bạn có một cái nhìn tại việc thực hiện sự bình đẳng Comparer NUnit trong GIT repo, bạn sẽ thấy rằng có một khối so dành riêng cho hai enumerations, trong đó có một ưu tiên cao hơn (đơn giản chỉ vì nó được đặt cao hơn) so với comparisons sử dụng giao diện IEquatable<T> hoặc phương pháp Object.Equals(Object) mà bạn đã triển khai hoặc quá tải trong lớp học PagedModel của mình.

Tôi không biết đây là lỗi hay tính năng, nhưng có thể bạn nên tự hỏi mình trước, nếu triển khai giao diện IEnumerable<ModelData> trực tiếp theo lớp PagedModel thực sự là lựa chọn tốt nhất, đặc biệt là vì PagedModel của bạn chỉ cần đếm ModelData trường hợp.

Có thể sẽ đủ (hoặc thậm chí tốt hơn) để cung cấp thông số ModelData thông qua một thuộc tính đơn giản chỉ đọc IEnumerable<ModelData> của lớp PagedModel. NUnit sẽ dừng tìm kiếm đối tượng PagedModel của bạn với một số đếm đơn giản là ModelData các đối tượng và kiểm tra đơn vị của bạn sẽ hoạt động như mong đợi.

Tùy chọn duy nhất khác là tùy chọn được đề xuất bởi csauve; để thực hiện một tùy chỉnh đơn giản IComparer cho PagedModel của bạn và cung cấp một thể hiện của nó cho tất cả khẳng định nơi bạn sẽ so sánh hai PagedModel trường hợp:

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

Nhưng điều này sẽ làm các xét nghiệm của bạn phức tạp hơn cần thiết và bạn sẽ luôn luôn phải hãy suy nghĩ sử dụng công cụ so sánh đặc biệt của bạn bất cứ khi nào bạn đang viết các kiểm tra bổ sung cho số PagedModel.