бросить проверенные исключения из макетов с мокито

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

Чтобы уточнить дальше.
Интерфейс List не предоставляет проверенное исключение для get(int index)метода, и поэтому Mockito терпит неудачу.
Когда вы создаете фиктивный список , Mockito будет использовать определение List .class, чтобы создать его макет.

Поведение, которое вы указываете с помощью when(list.get(0)).thenThrow(new SomeException()) not, не совпадает с сигнатурой метода в List API , потому что get(int index)метод неSomeException() генерирует ошибку, поэтому Mockito терпит неудачу.

Если вы действительно хотите это сделать, то предложите Mockito бросить a new RuntimeException()или, что еще лучше, бросить a, new ArrayIndexOutOfBoundsException()поскольку API указывает, что это единственное допустимое исключение, которое будет выдано.

Джон Энгельман
источник
Хотя мой настоящий код на самом деле не использовал List, ваш ответ применим и для вызова этого метода. Я издевался не над тем методом. Спасибо.
Артур Мальтсон
2
Дополнительно: Mocktio не будет жаловаться, если вы сделаете метод без каких-либо бросков, но вы также получите это исключение
dwana
8
Для Kotliners: Kotlin не имеет проверенных исключений, поэтому вы не можете обычно объявлять (в сигнатуре функции), что функция выдает исключение. Однако вы можете аннотировать функцию Throwsаннотацией, чтобы компилятор генерировал тот же байт-код, что и объявления бросков в эквивалентном коде Java. Смотрите [здесь] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/… ) для более подробной информации.
Джавад Садекзаде
1
Эта проверка применяется с момента выпуска Mockito 2.11.0 (см. 2.10.3) .
JJD
106

Обходной путь должен использовать willAnswer()метод.

Например, следующее работает (и не MockitoExceptionвыдает a, но на самом деле выдает проверенный 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
или используйте when (someObj.someMethod (stringArg1)). thenAnswer (invocation -> {throw new Exception ("abc msg");});
Дмитрий Алгазин
Отличный обходной путь, спасибо! Для Kotliners, которые хотят (1) использовать это как функцию расширения и (2) быть в состоянии передать несколько аргументов, как willThrow()обычно позволяет, я написал Gist
Дэвид Ферран
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

Кевин ABRIOUX
источник
1

Это работает для меня в Котлине:

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

Примечание. Бросьте любое определенное исключение, кроме Exception ().

Алок Гупта
источник
Именно то, что я искал, может выбросить любое исключение, кромеException
Наим Сарфраз