โยนการตรวจสอบข้อยกเว้นจาก mocks กับ Mockito


173

ฉันกำลังพยายามให้วัตถุที่เยาะเย้ยคนหนึ่งของฉันโยนข้อยกเว้นที่เลือกไว้เมื่อเรียกวิธีการเฉพาะ ฉันกำลังพยายามดังต่อไปนี้

@Test(expectedExceptions = SomeException.class)
public void throwCheckedException() {
    List<String> list = mock(List.class);
    when(list.get(0)).thenThrow(new SomeException());
    String test = list.get(0);
}

public class SomeException extends Exception {
}

อย่างไรก็ตามนั่นทำให้เกิดข้อผิดพลาดดังต่อไปนี้

org.testng.TestException: 
Expected exception com.testing.MockitoCheckedExceptions$SomeException but got org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: com.testing.MockitoCheckedExceptions$SomeException

ดูที่เอกสาร Mockito ที่พวกเขาใช้เท่านั้นRuntimeExceptionเป็นไปไม่ได้ที่จะโยนการตรวจสอบยกเว้นจากวัตถุจำลองด้วย Mockito?

คำตอบ:


221

ตรวจสอบใน Java API สำหรับรายการ วิธีการประกาศที่จะโยนเท่านั้นซึ่งทอดตัว คุณกำลังพยายามบอก Mockito ให้โยนข้อยกเว้นที่ไม่ถูกต้องโดยวิธีการเฉพาะนั้น
get(int index)IndexOutOfBoundExceptionRuntimeException
SomeException()นั้น

เพื่อชี้แจงเพิ่มเติม รายการอินเตอร์เฟซที่ไม่ได้จัดให้มีการยกเว้นการตรวจสอบจะถูกโยนจากวิธีการและนั่นคือเหตุผลที่ Mockito เป็นความล้มเหลว เมื่อคุณสร้างรายการที่เยาะเย้ย Mockito จะใช้คำนิยามของ List .class เพื่อสร้างจำลอง
get(int index)

พฤติกรรมที่คุณระบุด้วยwhen(list.get(0)).thenThrow(new SomeException()) ไม่ตรงกับลายเซ็นเมธอดใน List APIเนื่องจากget(int index)วิธีการไม่แสดงSomeException()ให้ Mockito ล้มเหลว

หากคุณต้องการทำสิ่งนี้จริงๆให้ Mockito ขว้าง a new RuntimeException()หรือดีกว่าการโยนnew ArrayIndexOutOfBoundsException()เนื่องจาก API ระบุว่านั่นเป็นข้อยกเว้นที่ถูกต้องเท่านั้นที่จะถูกโยนทิ้ง


ในขณะที่รหัสจริงของฉันไม่ได้ใช้รายการจริงคำตอบของคุณใช้สำหรับการเรียกใช้เมธอดนั้นเช่นกัน ฉันเยาะเย้ยวิธีที่ผิด ขอบคุณ.
Arthur Maltson

2
พิเศษ: Mocktio จะไม่บ่นถ้าคุณทำวิธีการโยนโดยไม่ต้องมีการโยน แต่คุณจะได้รับข้อยกเว้นนี้
dwana

8
สำหรับ Kotliners: Kotlin ไม่ได้ตรวจสอบข้อยกเว้นดังนั้นโดยปกติคุณจะไม่สามารถประกาศ (ในลายเซ็นฟังก์ชัน) ว่าฟังก์ชันส่งข้อยกเว้น อย่างไรก็ตามคุณสามารถใส่คำอธิบายประกอบฟังก์ชั่นด้วยThrowsคำอธิบายประกอบเพื่อให้คอมไพเลอร์สร้าง bytecode เช่นเดียวกับการประกาศการขว้างปาในโค้ด Java ที่เทียบเท่า ดู [ที่นี่] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/ … ) สำหรับรายละเอียดเพิ่มเติม
Javad Sadeqzadeh

1
การตรวจสอบนี้จะถูกบังคับใช้ตั้งแต่การเปิดตัวของMockito 2.11.0 (ดู 2.10.3)
JJD

106

วิธีแก้ปัญหาคือการใช้willAnswer()วิธีการ

ตัวอย่างงานต่อไปนี้ (และไม่ได้โยนMockitoExceptionแต่โยนการตรวจสอบExceptionตามความจำเป็นที่นี่) โดยใช้BDDMockito:

given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); });

เทียบเท่าสำหรับ Mockito ธรรมดาจะใช้doAnswerวิธีการ


9
หรือใช้เมื่อวิธีการส่งกลับwillAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1); void
Julien Kronegg

9
หรือใช้เมื่อ (someObj.someMethod (stringArg1)) thenAnswer (invocation -> {โยนข้อยกเว้นใหม่ ("abc msg");});
Dmitri Algazin

วิธีแก้ปัญหาที่ยอดเยี่ยมขอบคุณ! สำหรับ Kotliners ที่ต้องการ (1) ใช้สิ่งนั้นเป็นฟังก์ชั่นส่วนขยายได้อย่างราบรื่นและ (2) สามารถผ่าน args หลายอย่างที่willThrow()อนุญาตตามปกติฉันได้เขียนสรุปสาระสำคัญ
David Ferrand

2
หรือdoAnswerจากnhaarman.mockitokotlin2
hmac

6

โปรดทราบว่าโดยทั่วไป Mockito ไม่อนุญาตให้มีการขว้างปาข้อยกเว้นการตรวจสอบตราบใดที่ยกเว้นมีการประกาศในลายเซ็นข้อความ ตัวอย่างเช่นกำหนด

class BarException extends Exception {
  // this is a checked exception
}

interface Foo {
  Bar frob() throws BarException
}

การเขียนถูกกฎหมาย:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)

อย่างไรก็ตามหากคุณโยนข้อยกเว้นที่ตรวจสอบแล้วไม่ได้ประกาศไว้ในลายเซ็นวิธีการเช่น

class QuxException extends Exception {
  // a different checked exception
}

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)

Mockito จะล้มเหลวขณะทำงานด้วยข้อความทั่วไปที่ทำให้เข้าใจผิด:

Checked exception is invalid for this method!
Invalid: QuxException

นี้อาจทำให้คุณเชื่อว่าการตรวจสอบข้อยกเว้นทั่วไปจะได้รับการสนับสนุน แต่ในความเป็นจริง Mockito เป็นเพียงการพยายามที่จะบอกคุณว่านี้ยกเว้นการตรวจสอบไม่ถูกต้องสำหรับวิธีการนี้


5

มีวิธีแก้ปัญหาด้วย Kotlin:

given(myObject.myCall()).willAnswer {
    throw IOException("Ooops")
}

ที่ได้รับมาจากไหน

นำเข้า org.mockito.BDDMockito.given


1

สิ่งนี้ใช้ได้กับฉันใน Kotlin:

when(list.get(0)).thenThrow(new ArrayIndexOutOfBoundsException());

หมายเหตุ: โยนข้อยกเว้นที่กำหนดไว้นอกเหนือจากข้อยกเว้น ()


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