кинути перевірені Винятки з макетів з 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()

Щоб уточнити далі.
Інтерфейс списку не передбачає get(int index)відкидання перевіреного винятку з методу, і тому Mockito виходить з ладу.
Під час створення списку , що висміюється, Mockito використовуватиме визначення List .class для створення його макету.

Поведінка, яку ви вказуєте за допомогою when(list.get(0)).thenThrow(new SomeException()) , не відповідає методу підпису в API API , оскільки get(int index)метод не викидає,SomeException() тому Mockito виходить з ладу.

Якщо ви дійсно хочете це зробити, то Mockito киньте new RuntimeException()або ще краще киньте a, new ArrayIndexOutOfBoundsException()оскільки API вказує, що це єдиний дійсний виняток, який потрібно скинути.


Хоча мій реальний код насправді не використовував List, ваша відповідь застосовується і до цього виклику методу. Я знущався з неправильного методу. Дякую.
Артур Мальтсон

2
додатково: Mocktio не поскаржиться, якщо ви скористаєтеся методом без перекидання, але ви також отримаєте цей виняток
dwana

8
Для Kotliners: Kotlin не перевірив винятки, тому ви не можете звичайно заявити (у підписі функції), що функція видає виняток. Однак ви можете коментувати функцію Throwsанотацією, щоб змусити компілятор генерувати той самий байт-код, що і декларування кидків у еквівалентному коді 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.
Жульєн Кронегг

9
або використовувати, коли (someObj.someMethod (stringArg1)). thenAnswer (виклик -> {кинути новий виняток ("abc msg");});
Дмитро Алгазин

Чудовий спосіб вирішення, дякую! Для Kotliners, які хочуть (1) використовувати це безперешкодно як функцію розширення і (2) бути в змозі пройти кілька аргументів, як це willThrow()зазвичай дозволяє, я написав історію
Девід Ферран

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

Є рішення з Котліном:

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

Звідки походить

імпорт org.mockito.BDDMockito.given


1

Це працює для мене в Котліні:

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

Примітка. Викиньте будь-який визначений виняток, крім Exception ()


Тільки те, що я шукав, може кинути будь-яке Виняток, окрімException
Наєма Сарфраз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.