Hamcrest so sánh các bộ sưu tập


114

Tôi đang cố gắng so sánh 2 danh sách:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

Nhưng ý tưởng

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

Tôi nên viết nó như thế nào?

Câu trả lời:


161

Nếu bạn muốn khẳng định rằng hai danh sách là giống hệt nhau, đừng phức tạp hóa mọi thứ với Hamcrest:

assertEquals(expectedList, actual.getList());

Nếu bạn thực sự có ý định thực hiện so sánh không phân biệt thứ tự, bạn có thể gọi containsInAnyOrderphương thức varargs và cung cấp giá trị trực tiếp:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(Giả sử rằng danh sách của bạn là của String, thay vì Agent, đối với ví dụ này.)

Nếu bạn thực sự muốn gọi cùng một phương thức đó với nội dung của List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

Nếu không có điều này, bạn đang gọi phương thức với một đối số duy nhất và tạo một đối số Matchermong đợi khớp với một Iterabletrong đó mỗi phần tử là a List. Điều này không thể được sử dụng để khớp với a List.

Đó là, bạn không thể so khớp a List<Agent>với a Matcher<Iterable<List<Agent>>, đó là những gì mã của bạn đang cố gắng.


+1 cho "Nếu bạn thực sự muốn gọi cùng một phương thức đó với nội dung của Danh sách". Đáng buồn là tôi không thể tự mình giải quyết vấn đề đó. Đặc biệt là có một hàm tạo có trong một bộ sưu tập.
Eyad Ebrahim

3
@Tim Không khá lắm; containsInAnyOrderyêu cầu tất cả các phần tử đều có mặt, vì vậy khẳng định đầu tiên sẽ không thành công. Xem hasItemsliệu bạn có muốn kiểm tra xem có ít nhất các phần tử đó không.
Joe,

4
Nếu bạn sử dụng containsInAnyOrder, trước tiên bạn nên đảm bảo rằng cả hai danh sách có cùng kích thước ... Nếu actual.getList()xảy ra chứa "item1", "item3", "item2", kiểm tra sẽ vượt qua và có thể bạn muốn đảm bảo rằng nó chỉ chứa các mục được liệt kê ... Trong trường hợp đó, bạn có thể sử dụng assertThat(actual.getList().size(), equalTo(2));trước hàm chứaInAnyOrder, bằng cách này bạn đảm bảo rằng cả hai danh sách đều có nội dung giống nhau.
Martin

1
@Martin bạn đang nghĩ đến hasItems. Việc kiểm tra thêm là không cần thiết ở đây. Xem nhận xét cho Tim ở trên, và cả Hàm hasItems, contains và containsInAnyOrder khác nhau như thế nào?
Joe

1
Người dùng Kotlin : đừng quên thêm toán tử spread ( *expectedList.toTypedArray()) khi chuyển một mảng dưới dạng varargs!
James Bowman

62
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Phiên bản ngắn hơn của câu trả lời @ Joe không có tham số dư thừa.


28

Để bổ sung cho câu trả lời của @ Joe:

Hamcrest cung cấp cho bạn ba phương pháp chính để khớp danh sách:

contains Kiểm tra xem có khớp với tất cả các phần tử tính theo thứ tự không, nếu danh sách có nhiều phần tử hơn hoặc ít hơn, nó sẽ bị lỗi

containsInAnyOrder Kiểm tra để khớp tất cả các phần tử và không quan trọng thứ tự, nếu danh sách có nhiều hơn hoặc ít hơn các phần tử, sẽ không thành công

hasItems Chỉ kiểm tra các đối tượng được chỉ định, không quan trọng nếu danh sách có nhiều hơn

hasItem Chỉ kiểm tra một đối tượng, không quan trọng nếu danh sách có nhiều hơn

Tất cả chúng đều có thể nhận được danh sách các đối tượng và sử dụng equalsphương pháp để so sánh hoặc có thể được trộn với các đối sánh khác như @borjab đã đề cập:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains (E ...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html #containsInAnyOrder (java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems (T ...)


Đến bữa tiệc hơi muộn, nhưng cảm ơn bạn đã mô tả sự khác biệt giữa mỗi phương pháp.
Marcos de Andrade,

Quyết định tuyệt vời trong trường hợp các mục danh sách không thuộc loại nguyên thủy.
Stanislav Tsepa

Có một loại cách an toàn để làm điều này?
andresp

15

Với các thư viện Hamcrest hiện có (kể từ v.2.0.0.0), bạn buộc phải sử dụng phương thức Collection.toArray () trên Bộ sưu tập của mình để sử dụng hàm chứaInAnyOrder Matcher. Tốt hơn nhiều sẽ là thêm phương thức này như một phương thức riêng biệt vào org.hamcrest.Matchers:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

Trên thực tế, tôi đã thêm phương pháp này vào thư viện thử nghiệm tùy chỉnh của mình và sử dụng nó để tăng khả năng đọc các trường hợp thử nghiệm của tôi (do ít chi tiết hơn).


2
Tốt lắm, tôi sẽ sử dụng trình trợ giúp này. Thông điệp khẳng định ở đây có nhiều thông tin hơn: nó đặt tên từng mục còn thiếu, không chỉ: danh sách phải là elem1, elem2, .. elem99, nhưng tôi đã nhận được elem1, elem2, ..., elem98 - chúc may mắn tìm cái còn thiếu.
pihentagy

3

Đảm bảo rằng các Objects trong danh sách của bạn đã equals()được xác định trên chúng. Sau đó

    assertThat(generatedList,is(equalTo(expectedList)));

làm.


1

Đối với danh sách các đối tượng, bạn có thể cần một cái gì đó như sau:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

Sử dụng containsInAnyOrder nếu bạn không muốn kiểm tra thứ tự của các đối tượng.

Tái bút Bất kỳ trợ giúp nào để tránh cảnh báo được cung cấp sẽ thực sự được đánh giá cao.


-3

Để so sánh hai danh sách với thứ tự được sử dụng,

assertThat(actualList, contains("item1","item2"));

Điều này không trả lời câu hỏi.
kamczak

Nó một phần.
rvazquezglez

@rvazquezglez Ý bạn là gì? tại sao bạn nói như vậy? Kết quả của phương pháp nằm ngay trong môi trường của tôi.
niaomingjian

@niaomingjian Mã đang kiểm tra xem actualListcó chứa các phần tử bên trong containsmatcher hay không, điều này sẽ không thành công nếu các phần tử không theo cùng một thứ tự và cũng sẽ không thành công nếu nó chứa nhiều phần tử hơn hoặc thiếu một phần tử.
rvazquezglez

@rvazquezglez vì vậy mục đích của mã là để kiểm tra sự bình đẳng chính xác (cùng độ dài, giá trị và thứ tự) trong hai danh sách, phải không?
niaomingjian
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.