การโทรกลับแบบจำลองและการรับค่าอาร์กิวเมนต์


89

ฉันไม่มีโชคเลยที่ได้รับ Mockito เพื่อจับค่าอาร์กิวเมนต์ของฟังก์ชัน! ฉันล้อเลียนดัชนีของเครื่องมือค้นหาและแทนที่จะสร้างดัชนีฉันแค่ใช้แฮช

// Fake index for solr
Hashmap<Integer,Document> fakeIndex;

// Add a document 666 to the fakeIndex
SolrIndexReader reader = Mockito.mock(SolrIndexReader.class);

// Give the reader access to the fake index
Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))

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

Mockito.when(reader.document(0)).thenReturn(document(fakeIndex(0))
Mockito.when(reader.document(1)).thenReturn(document(fakeIndex(1))
....
Mockito.when(reader.document(n)).thenReturn(document(fakeIndex(n))

ผมมองไปที่ส่วนของการเรียกกลับในการใช้ Mockitoหน้า น่าเสียดายที่มันไม่ใช่ Java และฉันไม่สามารถตีความว่ามันทำงานใน Java ได้

แก้ไข (เพื่อความชัดเจน): ฉันจะให้ Mockito จับอาร์กิวเมนต์ X และส่งผ่านไปยังฟังก์ชันของฉันได้อย่างไร ฉันต้องการให้ค่าที่แน่นอน (หรืออ้างอิง) ของ X ส่งผ่านไปยังฟังก์ชัน

ฉันไม่ต้องการแจกแจงทุกกรณีและการโต้แย้งตามอำเภอใจจะใช้ไม่ได้เพราะฉันกำลังทดสอบผลลัพธ์ที่แตกต่างกันสำหรับข้อความค้นหา

หน้า Mockito กล่าวว่า

val mockedList = mock[List[String]]
mockedList.get(anyInt) answers { i => "The parameter is " + i.toString } 

นั่นไม่ใช่ java และฉันไม่รู้วิธีแปลเป็น java หรือส่งผ่านสิ่งที่เกิดขึ้นในฟังก์ชัน


ฉันไม่แน่ใจว่าฉันเข้าใจสิ่งที่ล้มเหลวสำหรับคุณ การเรียกร้องของคุณMockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))ควรตั้งค่าวัตถุจำลองให้คุณ จะเกิดอะไรขึ้นเมื่อคุณโทรreader.document(666)?
คาเฟอีนสูง

666 ทำงานได้ดี อย่างไรก็ตามฉันต้องการส่งผ่านจำนวนเฉพาะ X และรับผลลัพธ์ของ fakeIndex (X) ฉันมีเอกสารที่เป็นไปได้จำนวนมากเพื่อทดสอบการสืบค้นและฉันไม่ต้องการป้อนทั้งหมด
nflacco

คำตอบ:


104

ฉันไม่เคยใช้ Mockito แต่ต้องการเรียนรู้ดังนั้นไปเลย ถ้ามีคนตอบน้อยกว่าฉันก็ลองตอบก่อนสิ!

Mockito.when(reader.document(anyInt())).thenAnswer(new Answer() {
 public Object answer(InvocationOnMock invocation) {
     Object[] args = invocation.getArguments();
     Object mock = invocation.getMock();
     return document(fakeIndex((int)(Integer)args[0]));
     }
 });

2
ผมเพิ่งสังเกตเห็นการเชื่อมโยงทางด้านขวาไปMockito: วิธีการทำวิธีการกลับอาร์กิวเมนต์ที่ถูกส่งผ่านไปมัน ดูเหมือนว่าฉันจะอยู่ใกล้ ๆ ถ้าไม่เห็น
Ed Staub

ชื่อเสียงของผู้ใช้ที่แข็งแกร่ง (666) กับความสัมพันธ์ของคำถามดั้งเดิม! ที่ได้ผลดีมาก เฉพาะการเปลี่ยนแปลงที่ฉันทำเพื่อรวบรวมสิ่งต่างๆเท่านั้นที่ถูกเผยแพร่ต่อหน้าคำตอบของวัตถุ (การเรียกใช้ InvocationOnMock) ....
nflacco

54

ตรวจสอบ ArgumentCaptors:

https://site.mockito.org/javadoc/current/org/mockito/ArgumentCaptor.html

ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
Mockito.when(reader.document(argument.capture())).thenAnswer(
  new Answer() {
    Object answer(InvocationOnMock invocation) {
      return document(argument.getValue());
    }
  });

3
ว้าวฉันไม่รู้ว่าคุณสามารถใช้ArgumentCaptors เพื่อทำให้ขาดได้ มีคำเตือนเกี่ยวกับเรื่องนี้ในลิงค์นั้น ดำเนินการด้วยความระมัดระวัง
einnocent

3
ใช่คุณพูดถูก ควรใช้แคปเตอร์กับการยืนยันเท่านั้น
qualidafial

41

คุณอาจต้องการใช้การตรวจสอบ () ร่วมกับ ArgumentCaptor เพื่อรับรองการดำเนินการในการทดสอบและ ArgumentCaptor เพื่อประเมินอาร์กิวเมนต์:

ArgumentCaptor<Document> argument = ArgumentCaptor.forClass(Document.class);
verify(reader).document(argument.capture());
assertEquals(*expected value here*, argument.getValue());

เห็นได้ชัดว่าค่าของอาร์กิวเมนต์สามารถเข้าถึงได้ผ่านทางอาร์กิวเมนต์ getValue () สำหรับการจัดการ / ตรวจสอบเพิ่มเติมหรือสิ่งที่คุณต้องการจะทำ


2
คำตอบที่ดีที่สุด: ตรงไปตรงมาเข้าใจง่าย
Radu Cugut

ไม่ตอบคำถาม คำถามเกี่ยวกับ Mockito เมื่อใดและไม่ตรวจสอบ
seBaka28

@ seBaka28 ทางออกที่ดีที่สุดในการรับอาร์กิวเมนต์คือตัวจับอาร์กิวเมนต์ ArgumentCaptors ควรใช้กับการตรวจสอบโดยผู้เขียน Mockito ดังนั้นฉันจึงต้องการให้คำตอบแบบเต็มมุมมอง หากคุณเลือกที่จะไม่ใช้ด้วยตัวคุณเองนั่นคือทางเลือกของคุณ แต่ไม่แนะนำ แก้ไข: ฉันไม่เห็นว่าสิ่งนี้จะทำให้การโหวตลดลง แต่นั่นก็เป็นทางเลือกของคุณเช่นกัน
fl0w

1
เพราะไม่ตอบโจทย์. ใช่ ArgumentCaptor นั้นยอดเยี่ยมเมื่อคุณต้องการจับอาร์กิวเมนต์ แต่คุณไม่สามารถใช้ร่วมกับเมื่อ (... ) แล้วรีเทิร์น () ซึ่งเป็นสิ่งที่ OP พยายามทำ: จากพารามิเตอร์บางอย่างซึ่งเป็นบริการจำลอง ควรจะส่งคืนวัตถุเฉพาะ
seBaka28

1
@YuraHoy นั่นคือข้อความแสดงข้อผิดพลาดมาตรฐานเมื่อคุณใช้การตรวจสอบและวัตถุหรือวิธีการถูกเรียกบ่อยกว่าที่คุณบอกว่าจะต้องตรวจสอบ คุณสามารถเปลี่ยนจำนวนความคาดหวังได้โดยการเพิ่มอาร์กิวเมนต์ times (n) ดังต่อไปนี้: ตรวจสอบ (ผู้อ่าน, ครั้ง (5)) - คาดว่าจะมีการโต้ตอบ 5 ครั้ง สำหรับข้อมูลอ้างอิงโปรดดู: baeldung.com/mockito-verify
fl0w

14

ด้วย Java 8 สิ่งนี้อาจเป็นดังนี้:

Mockito.when(reader.document(anyInt())).thenAnswer(
  (InvocationOnMock invocation) -> document(invocation.getArguments()[0]));

ฉันสมมติว่านั่นdocumentคือแผนที่

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