Hamcrest เปรียบเทียบคอลเล็กชัน


114

ฉันกำลังพยายามเปรียบเทียบ 2 รายการ:

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

แต่ความคิด

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)

ควรเขียนอย่างไร

คำตอบ:


161

หากคุณต้องการยืนยันว่าทั้งสองรายการเหมือนกันอย่าซับซ้อนกับ Hamcrest:

assertEquals(expectedList, actual.getList());

หากคุณตั้งใจจะทำการเปรียบเทียบแบบไม่คำนึงถึงคำสั่งซื้อจริงๆคุณสามารถเรียกใช้containsInAnyOrderเมธอด varargs และระบุค่าได้โดยตรง:

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

(สมมติว่ารายการของคุณเป็นStringมากกว่าAgentเช่นนี้.)

หากคุณต้องการเรียกใช้วิธีการเดียวกันกับเนื้อหาของ a List:

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

หากไม่มีสิ่งนี้คุณจะเรียกเมธอดด้วยอาร์กิวเมนต์เดียวและสร้างMatcherที่คาดว่าจะจับคู่โดยIterableที่แต่ละองค์ประกอบคือ a List. ไม่สามารถใช้เพื่อจับคู่ไฟล์List.

นั่นคือคุณไม่สามารถจับคู่ a List<Agent>กับ a Matcher<Iterable<List<Agent>>ซึ่งเป็นสิ่งที่รหัสของคุณพยายาม


+1 สำหรับ "หากคุณต้องการเรียกวิธีการเดียวกันกับเนื้อหาของรายการ" น่าเศร้าที่ฉันไม่สามารถแก้ไขตัวเองได้ พิเศษที่มีตัวสร้างที่ใช้ในคอลเลกชัน
Eyad Ebrahim

3
@ ทิมไม่ค่อย; containsInAnyOrderต้องการให้องค์ประกอบทั้งหมดมีอยู่ดังนั้นการยืนยันครั้งแรกจะล้มเหลว ดูhasItemsถ้าคุณต้องการที่จะตรวจสอบว่าอย่างน้อยองค์ประกอบเหล่านั้นมีอยู่
โจ

4
หากคุณใช้ containsInAnyOrder ก่อนอื่นคุณควรตรวจสอบให้แน่ใจว่าทั้งสองรายการมีขนาดเท่ากัน ... หากactual.getList()มี"item1", "item3", "item2"อยู่การทดสอบจะผ่านไปและบางทีคุณอาจต้องการตรวจสอบให้แน่ใจว่ามีเฉพาะรายการในรายการเท่านั้น ... ในกรณีนี้คุณสามารถใช้assertThat(actual.getList().size(), equalTo(2));ก่อนหน้า containsInAnyOrder วิธีนี้จะทำให้คุณแน่ใจว่าทั้งสองรายการมีเนื้อหาเหมือนกัน
Martin

1
@ Martin hasItemsคุณคิดว่าการ ที่นี่ไม่จำเป็นต้องตรวจสอบเพิ่มเติม ดูความคิดเห็นของ Tim ด้านบนและhasItems ของ Hamcrest ประกอบด้วยและประกอบด้วยInAnyOrderแตกต่างกันอย่างไร
โจ

1
ผู้ใช้ Kotlin : อย่าลืมเพิ่มตัวดำเนินการกระจาย ( *expectedList.toTypedArray()) เมื่อส่งอาร์เรย์เป็น varargs!
James Bowman

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

คำตอบของ @ Joe เวอร์ชันสั้นกว่าโดยไม่มีพารามิเตอร์ซ้ำซ้อน


28

เพื่อเติมเต็มคำตอบของ @ Joe:

Hamcrest มีสามวิธีหลักในการจับคู่รายการ:

contains ตรวจสอบการจับคู่องค์ประกอบทั้งหมดในการนับลำดับหากรายการมีองค์ประกอบมากหรือน้อยก็จะล้มเหลว

containsInAnyOrder ตรวจสอบการจับคู่องค์ประกอบทั้งหมดและไม่สำคัญว่าลำดับหากรายการมีองค์ประกอบมากหรือน้อยจะล้มเหลว

hasItems ตรวจสอบเฉพาะสำหรับวัตถุที่ระบุไม่สำคัญว่ารายการมีมากกว่านี้หรือไม่

hasItem ตรวจสอบวัตถุเพียงชิ้นเดียวไม่สำคัญว่ารายการมีมากกว่านี้หรือไม่

พวกเขาทั้งหมดสามารถรับรายการวัตถุและใช้equalsวิธีการเปรียบเทียบหรือสามารถผสมกับผู้จับคู่อื่น ๆ เช่น @borjab ที่กล่าวถึง:

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


สายไปหน่อย แต่ขอบคุณสำหรับคำอธิบายความแตกต่างระหว่างแต่ละวิธี
Marcos de Andrade

การตัดสินใจที่ดีในกรณีรายการไม่ใช่ประเภทดั้งเดิม
Stanislav

มีวิธีที่ปลอดภัยในการทำเช่นนี้หรือไม่?
andresp

15

ด้วยไลบรารี Hamcrest ที่มีอยู่ (ณ v.2.0.0.0) คุณถูกบังคับให้ใช้เมธอด Collection.toArray () บนคอลเล็กชันของคุณเพื่อใช้มีInAnyOrder Matcher ที่ดีกว่าคือการเพิ่มสิ่งนี้เป็นวิธีการแยกต่างหากใน 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());
}

จริงๆแล้วฉันลงเอยด้วยการเพิ่มวิธีนี้ลงในไลบรารีการทดสอบที่กำหนดเองของฉันและใช้เพื่อเพิ่มความสามารถในการอ่านกรณีทดสอบของฉัน (เนื่องจากความละเอียดน้อยกว่า)


2
ดีฉันจะใช้ตัวช่วยนี้ ข้อความยืนยันที่นี่เป็นข้อมูลมากกว่า: มันตั้งชื่อรายการที่หายไปทีละรายการไม่ใช่แค่: รายการควรเป็น elem1, elem2, .. elem99 แต่ฉันได้รับ elem1, elem2, ... , elem98 - ขอให้โชคดี ค้นหาสิ่งที่หายไป
pihentagy

3

ตรวจสอบให้แน่ใจว่ารายการObjectในรายการของคุณได้equals()กำหนดไว้ แล้วก็

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

โรงงาน


1

สำหรับรายการวัตถุคุณอาจต้องการสิ่งนี้:

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")))));
}

ใช้containsInAnyOrderถ้าคุณไม่ต้องการตรวจสอบลำดับของวัตถุ

ป.ล. ความช่วยเหลือใด ๆ เพื่อหลีกเลี่ยงคำเตือนที่ได้รับการสนับสนุนจะได้รับการชื่นชมจริงๆ


-3

หากต้องการเปรียบเทียบสองรายการกับคำสั่งซื้อที่เก็บรักษาไว้

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

สิ่งนี้ไม่ตอบคำถาม
kamczak

มันทำบางส่วน
rvazquezglez

@rvazquezglez คุณหมายถึงอะไร? ทำไมคุณพูดแบบนั้น? ผลลัพธ์ของวิธีการนี้เหมาะสมกับสภาพแวดล้อมของฉัน
niaomingjian

@niaomingjian รหัสกำลังตรวจสอบว่าactualListมีองค์ประกอบภายในcontainsตัวจับคู่ซึ่งจะล้มเหลวหากองค์ประกอบไม่อยู่ในลำดับเดียวกันและจะล้มเหลวเช่นกันหากมีองค์ประกอบมากกว่าหรือขาดไป
rvazquezglez

@rvazquezglez ดังนั้นวัตถุประสงค์ของรหัสคือเพื่อตรวจสอบความเท่าเทียมกันที่แน่นอน (ความยาวค่าและลำดับเท่ากัน) ในสองรายการใช่ไหม
niaomingjian
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.