matchers Mockitoวิธีการแบบคงที่และโทรไปยังวิธีการเหล่านั้นซึ่งยืนอยู่ในข้อโต้แย้งในช่วงสายไปและwhenverify
Hamcrest matchers (เวอร์ชันที่เก็บถาวร) (หรือตัวจับคู่แบบ Hamcrest) เป็นอินสแตนซ์อ็อบเจ็กต์ที่ไม่มีสถานะและมีวัตถุประสงค์ทั่วไปที่ใช้Matcher<T>และแสดงวิธีการmatches(T)ที่ส่งคืนจริงหากอ็อบเจ็กต์ตรงกับเกณฑ์ของ Matcher มีวัตถุประสงค์เพื่อให้ปราศจากผลข้างเคียงและโดยทั่วไปจะใช้ในการยืนยันเช่นด้านล่าง
/* Mockito */  verify(foo).setPowerLevel(gt(9000));
/* Hamcrest */ assertThat(foo.getPowerLevel(), is(greaterThan(9000)));
Mockito matchers มีอยู่แยกต่างหากจากตัวจับคู่แบบ Hamcrest เพื่อให้คำอธิบายของนิพจน์ที่ตรงกันพอดีกับการเรียกใช้เมธอดโดยตรง : Mockito matchers จะส่งคืนTโดยที่วิธีการจับคู่ Hamcrest จะส่งคืนอ็อบเจ็กต์ Matcher (ประเภทMatcher<T>)
matchers Mockito ถูกเรียกด้วยวิธีการแบบคงที่เช่นeq, any, gtและstartsWithบนและorg.mockito.Matchers org.mockito.AdditionalMatchersนอกจากนี้ยังมีอะแดปเตอร์ซึ่งมีการเปลี่ยนแปลงในรุ่น Mockito:
- สำหรับ Mockito 1.x การMatchersเรียกใช้บางสาย (เช่นintThatหรือargThat) คือ Mockito matchers ที่ยอมรับ Hamcrest matchers เป็นพารามิเตอร์โดยตรงArgumentMatcher<T>ขยายorg.hamcrest.Matcher<T>ซึ่งใช้ในการเป็นตัวแทน Hamcrest ภายในและเป็นคลาสพื้นฐานของ Hamcrest matcherแทนที่จะเป็นMockito matcher ประเภทใด ๆ
- สำหรับ Mockito 2.0+ Mockito ไม่มีการพึ่งพาโดยตรงกับ Hamcrest อีกต่อไป Matchersเรียกวลีเป็นintThatหรือargThatห่อArgumentMatcher<T>วัตถุที่ไม่ได้ใช้งานอีกต่อไปorg.hamcrest.Matcher<T>แต่ใช้ในลักษณะที่คล้ายกัน อะแดปเตอร์ Hamcrest เช่นargThatและintThatยังคงมีอยู่ แต่ได้ย้ายไปที่MockitoHamcrestแทน
ไม่ว่าผู้จับคู่จะเป็นแฮมเครสต์หรือสไตล์แฮมเครสต์ก็สามารถปรับเปลี่ยนได้ดังนี้:
/* Mockito matcher intThat adapting Hamcrest-style matcher is(greaterThan(...)) */
verify(foo).setPowerLevel(intThat(is(greaterThan(9000))));
ในข้อความข้างต้น: foo.setPowerLevelเป็นวิธีการที่ยอมรับintไฟล์. is(greaterThan(9000))ส่งคืน a Matcher<Integer>ซึ่งไม่สามารถใช้เป็นsetPowerLevelอาร์กิวเมนต์ได้ ตัวจับคู่ Mockito intThatห่อ Matcher แบบ Hamcrest และส่งคืนintเพื่อให้สามารถปรากฏเป็นอาร์กิวเมนต์ได้ ตัวจับคู่ Mockito ต้องการgt(9000)รวมนิพจน์ทั้งหมดไว้ในการเรียกเพียงครั้งเดียวดังเช่นในบรรทัดแรกของโค้ดตัวอย่าง
ผู้จับคู่ทำอะไร / ส่งคืน
when(foo.quux(3, 5)).thenReturn(true);
เมื่อไม่ใช้ตัวจับคู่อาร์กิวเมนต์ Mockito จะบันทึกค่าอาร์กิวเมนต์ของคุณและเปรียบเทียบกับequalsวิธีการของพวกเขา
when(foo.quux(eq(3), eq(5))).thenReturn(true);    // same as above
when(foo.quux(anyInt(), gt(5))).thenReturn(true); // this one's different
เมื่อคุณเรียกตัวจับคู่เช่นanyหรือgt(มากกว่า) Mockito จะจัดเก็บวัตถุที่จับคู่ซึ่งทำให้ Mockito ข้ามการตรวจสอบความเท่าเทียมกันนั้นและใช้การจับคู่ที่คุณเลือก ในกรณีที่จัดargumentCaptor.capture()เก็บตัวจับคู่ที่บันทึกอาร์กิวเมนต์แทนเพื่อการตรวจสอบในภายหลัง
matchers กลับค่าหุ่นnullดังกล่าวเป็นศูนย์คอลเลกชันที่ว่างเปล่าหรือ Mockito พยายามที่จะกลับมาเป็นที่ปลอดภัยค่าหุ่นที่เหมาะสมเช่น 0 anyInt()หรือany(Integer.class)หรือที่ว่างเปล่าสำหรับList<String> anyListOf(String.class)เนื่องจากการลบประเภท Mockito จึงขาดข้อมูลประเภทที่จะส่งคืนค่าใด ๆ แต่nullสำหรับany()หรือargThat(...)ซึ่งอาจทำให้เกิด NullPointerException ได้หากพยายาม "unbox อัตโนมัติ" เป็นnullค่าดั้งเดิม
Matchers ชอบeqและgtรับค่าพารามิเตอร์ ตามหลักการแล้วควรคำนวณค่าเหล่านี้ก่อนที่การตัด / การตรวจสอบจะเริ่มขึ้น การโทรเยาะเย้ยในระหว่างการล้อเลียนการโทรสายอื่นอาจรบกวนการสะดุดได้
ไม่สามารถใช้เมธอด Matcher เป็นค่าส่งคืน ไม่มีทางที่จะใช้วลีthenReturn(anyInt())หรือthenReturn(any(Foo.class))ใน Mockito ได้เช่น Mockito จำเป็นต้องทราบอย่างชัดเจนว่าอินสแตนซ์ใดที่จะส่งคืนในการโทรที่ถูกขีดฆ่าและจะไม่เลือกค่าตอบแทนโดยพลการให้คุณ
รายละเอียดการดำเนินการ
matchers จะถูกเก็บไว้ (เป็น matchers วัตถุ Hamcrest สไตล์) ในสแต็คที่มีอยู่ในระดับที่เรียกว่าArgumentMatcherStorage MockitoCore และ Matchers ต่างเป็นเจ้าของอินสแตนซ์ThreadSafeMockingProgressซึ่งมีอินสแตนซ์ ThreadLocal ที่ถือ MockingProgress แบบคงที่ มันนี้MockingProgressImplที่ถือคอนกรีตArgumentMatcherStorageImpl ดังนั้นสถานะจำลองและการจับคู่จึงเป็นแบบคงที่ แต่มีการกำหนดขอบเขตเธรดอย่างสม่ำเสมอระหว่างคลาส Mockito และ Matchers
ส่วนใหญ่โทรจับคู่เพียง แต่เพิ่มไปยังกองนี้มีข้อยกเว้นสำหรับ matchers เหมือนand,ornotและ สิ่งนี้สอดคล้องอย่างสมบูรณ์กับ (และอาศัย) ลำดับการประเมินของ Javaซึ่งประเมินอาร์กิวเมนต์จากซ้ายไปขวาก่อนที่จะเรียกใช้เมธอด:
when(foo.quux(anyInt(), and(gt(10), lt(20)))).thenReturn(true);
[6]      [5]  [1]       [4] [2]     [3]
นี่จะ:
- เพิ่มanyInt()ลงในสแต็ก
- เพิ่มgt(10)ลงในสแต็ก
- เพิ่มlt(20)ลงในสแต็ก
- ลบgt(10)และและเพิ่มlt(20)and(gt(10), lt(20))
- โทรfoo.quux(0, 0)ซึ่ง (ยกเว้นกรณีที่ค้างอยู่เป็นอย่างอื่น)falseผลตอบแทนที่คุ้มค่าเริ่มต้น Mockito ภายในทำเครื่องหมายquux(int, int)ว่าเป็นการโทรล่าสุด
- การโทรwhen(false)ซึ่งจะละทิ้งอาร์กิวเมนต์และเตรียมที่จะใช้วิธีการต้นขั้วที่quux(int, int)ระบุใน 5 สถานะที่ถูกต้องมีเพียงสองสถานะเท่านั้นที่มีความยาวสแต็ก 0 (ความเท่าเทียมกัน) หรือ 2 (ตัวจับคู่) และมีตัวจับคู่สองตัวบนสแต็ก (ขั้นตอนที่ 1 และ 4) ดังนั้น Mockito จะตัดเมธอดด้วยตัวany()จับคู่สำหรับอาร์กิวเมนต์แรกและand(gt(10), lt(20))สำหรับอาร์กิวเมนต์ที่สองและล้างสแต็ก
นี่แสดงให้เห็นกฎบางประการ:
- Mockito ไม่สามารถบอกความแตกต่างระหว่างและ- quux(anyInt(), 0)- quux(0, anyInt())ทั้งคู่ดูเหมือนโทร- quux(0, 0)คุยกับ int matcher หนึ่งคนในสแต็ก ดังนั้นหากคุณใช้ตัวจับคู่หนึ่งตัวคุณจะต้องจับคู่อาร์กิวเมนต์ทั้งหมด
 
- เพื่อโทรไม่สำคัญเพียง แต่สิ่งที่ทำให้การทำงานทั้งหมด โดยทั่วไปแล้วการแยกตัวจับคู่ไปยังตัวแปรจะไม่ได้ผลเพราะโดยปกติจะเปลี่ยนลำดับการโทร อย่างไรก็ตามการแยกตัวจับคู่เป็นวิธีการทำงานได้ดี - int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */  when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.
 
- กองซ้อนเปลี่ยนแปลงบ่อยพอที่ Mockito ไม่สามารถตำรวจได้อย่างระมัดระวัง สามารถตรวจสอบสแต็กได้เฉพาะเมื่อคุณโต้ตอบกับ Mockito หรือล้อเลียนและต้องยอมรับตัวจับคู่โดยไม่ทราบว่าถูกใช้ทันทีหรือละทิ้งโดยไม่ตั้งใจ ตามทฤษฎีแล้วสแต็กควรว่างเปล่าเสมอนอกการเรียก- whenหรือ- verifyแต่ Mockito ไม่สามารถตรวจสอบได้โดยอัตโนมัติ- Mockito.validateMockitoUsage()คุณสามารถตรวจสอบด้วยตนเอง
 
- ในการโทรหา- whenMockito จะเรียกเมธอดที่เป็นปัญหาซึ่งจะทำให้เกิดข้อยกเว้นหากคุณได้ขีดฆ่าวิธีการที่จะโยนข้อยกเว้น (หรือต้องการค่าที่ไม่ใช่ศูนย์หรือไม่ใช่ค่าว่าง)- doReturnและ- doAnswer(ฯลฯ ) ไม่เรียกใช้วิธีการจริงและมักเป็นทางเลือกที่มีประโยชน์
 
- หากคุณเรียกวิธีการจำลองที่อยู่ตรงกลางของการ- eqขีดทับ(เช่นการคำนวณคำตอบสำหรับตัวจับคู่) Mockito จะตรวจสอบความยาวสแต็กเทียบกับการเรียกนั้นแทนและอาจล้มเหลว
 
- หากคุณพยายามทำบางสิ่งที่ไม่ดีเช่นการขีดฆ่า/ การตรวจสอบวิธีสุดท้าย Mockito จะเรียกวิธีการจริงและทิ้งตัวจับคู่พิเศษไว้ในสแต็ก - finalเรียกวิธีการอาจจะไม่โยนยกเว้น แต่คุณอาจจะได้รับการInvalidUseOfMatchersExceptionจาก matchers จรจัดเมื่อคุณมีปฏิสัมพันธ์ต่อไปด้วยจำลอง
 
ปัญหาทั่วไป
- InvalidUseOfMatchersException : - 
- ตรวจสอบว่าทุกอาร์กิวเมนต์มีการเรียกจับคู่เพียงครั้งเดียวถ้าคุณใช้ตัวจับคู่เลยและคุณไม่ได้ใช้ตัวจับคู่นอกการเรียก- whenหรือ- verifyไม่ควรใช้ Matchers เป็นค่าที่ส่งคืนหรือฟิลด์ / ตัวแปร
 
- ตรวจสอบว่าคุณไม่ได้เรียกการล้อเลียนซึ่งเป็นส่วนหนึ่งของการให้อาร์กิวเมนต์ที่ตรงกัน 
- ตรวจสอบว่าคุณไม่ได้พยายามขีดฆ่า / ยืนยันวิธีสุดท้ายด้วยตัวจับคู่ เป็นวิธีที่ดีในการทิ้งตัวจับคู่ไว้ในสแต็กและเว้นแต่วิธีสุดท้ายของคุณจะทำให้เกิดข้อยกเว้นนี่อาจเป็นครั้งเดียวที่คุณรู้ว่าวิธีที่คุณกำลังเยาะเย้ยถือเป็นที่สิ้นสุด 
 
- NullPointerException พร้อมอาร์กิวเมนต์ดั้งเดิม: - (Integer) any()คืนค่า null ในขณะที่- any(Integer.class)ส่งกลับ 0; สิ่งนี้อาจทำให้เกิด- NullPointerExceptionถ้าคุณคาดหวังว่าจะได้รับ- intแทนที่จะเป็นจำนวนเต็ม ไม่ว่าในกรณีใดก็ตามชอบ- anyInt()ซึ่งจะคืนค่าศูนย์และข้ามขั้นตอนการชกมวยอัตโนมัติ
 
- NullPointerException หรือข้อยกเว้นอื่น ๆ : Call to - when(foo.bar(any())).thenReturn(baz)จะเรียก จริง- foo.bar(null)ซึ่งคุณอาจถูกขีดฆ่าเพื่อโยนข้อยกเว้นเมื่อได้รับอาร์กิวเมนต์ว่าง สลับไปข้ามพฤติกรรม- doReturn(baz).when(foo).bar(any())stubbed
 
การแก้ไขปัญหาทั่วไป
- ใช้MockitoJUnitRunnerหรือเรียกอย่างชัดเจน- validateMockitoUsageในวิธี- tearDownหรือของคุณ- @After(ซึ่งนักวิ่งจะทำเพื่อคุณโดยอัตโนมัติ) วิธีนี้จะช่วยตรวจสอบว่าคุณใช้ตัวจับคู่ผิดหรือไม่
 
- สำหรับวัตถุประสงค์ในการแก้ไขจุดบกพร่องให้เพิ่มการโทรลง- validateMockitoUsageในโค้ดของคุณโดยตรง สิ่งนี้จะส่งผลหากคุณมีอะไรในกองซึ่งเป็นสัญญาณเตือนที่ดีถึงอาการไม่ดี