diff --git a/README.md b/README.md index 63d9a09ac..6fa847839 100644 --- a/README.md +++ b/README.md @@ -1321,6 +1321,7 @@ An Answer can be followed up by one or more additional answers. |`returnsMany list`|specify that the matched call returns a value from the list, with subsequent calls returning the next element| |`returnsArgument(n)`|specify that the matched call returns the nth argument of that call| |`throws ex`|specify that the matched call throws an exception| +|`throwsMany ex`| specify that the matched call throws an exception from the list, with subsequent calls throwing the next exception| |`answers { code }`|specify that the matched call answers with a code block scoped with `answer scope`| |`coAnswers { code }`|specify that the matched call answers with a coroutine code block with `answer scope`| |`answers answerObj`|specify that the matched call answers with an Answer object| @@ -1341,6 +1342,7 @@ So this is similar to the `returnsMany` semantics. |`andThen value`|specify that the matched call returns one specified value| |`andThenMany list`|specify that the matched call returns a value from the list, with subsequent calls returning the next element| |`andThenThrows ex`|specify that the matched call throws an exception| +|`andThenThrowsMany ex`|specify that the matched call throws an exception from the list, with subsequent calls throwing the next exception| |`andThen { code }`|specify that the matched call answers with a code block scoped with `answer scope`| |`coAndThen { code }`|specify that the matched call answers with a coroutine code block with `answer scope`| |`andThenAnswer answerObj`|specify that the matched call answers with an Answer object| diff --git a/modules/mockk-dsl/api/mockk-dsl.api b/modules/mockk-dsl/api/mockk-dsl.api index e2bcb72a0..1be7af8fc 100644 --- a/modules/mockk-dsl/api/mockk-dsl.api +++ b/modules/mockk-dsl/api/mockk-dsl.api @@ -486,6 +486,7 @@ public final class io/mockk/MockKAdditionalAnswerScope { public final fun andThenMany (Ljava/util/List;)Lio/mockk/MockKAdditionalAnswerScope; public final fun andThenMany ([Ljava/lang/Object;)Lio/mockk/MockKAdditionalAnswerScope; public final fun andThenThrows (Ljava/lang/Throwable;)Lio/mockk/MockKAdditionalAnswerScope; + public final fun andThenThrowsMany (Ljava/util/List;)Lio/mockk/MockKAdditionalAnswerScope; public final fun coAndThen (Lkotlin/jvm/functions/Function3;)Lio/mockk/MockKAdditionalAnswerScope; } @@ -927,6 +928,7 @@ public final class io/mockk/MockKStubScope { public final fun returnsMany (Ljava/util/List;)Lio/mockk/MockKAdditionalAnswerScope; public final fun returnsMany ([Ljava/lang/Object;)Lio/mockk/MockKAdditionalAnswerScope; public final fun throws (Ljava/lang/Throwable;)Lio/mockk/MockKAdditionalAnswerScope; + public final fun throwsMany (Ljava/util/List;)Lio/mockk/MockKAdditionalAnswerScope; } public final class io/mockk/MockKUnmockKCompositeScope : io/mockk/MockKUnmockKScope { diff --git a/modules/mockk-dsl/src/commonMain/kotlin/io/mockk/API.kt b/modules/mockk-dsl/src/commonMain/kotlin/io/mockk/API.kt index c467cd206..cf8c484b3 100644 --- a/modules/mockk-dsl/src/commonMain/kotlin/io/mockk/API.kt +++ b/modules/mockk-dsl/src/commonMain/kotlin/io/mockk/API.kt @@ -2133,6 +2133,9 @@ class MockKStubScope( infix fun throws(ex: Throwable) = answers(ThrowingAnswer(ex)) + infix fun throwsMany(exList: List): MockKAdditionalAnswerScope = + this answers (ManyAnswersAnswer(exList.map { ThrowingAnswer(it) })) + infix fun answers(answer: MockKAnswerScope.(Call) -> T) = answers(FunctionAnswer { MockKAnswerScope(lambda, it).answer(it) }) @@ -2183,6 +2186,9 @@ class MockKAdditionalAnswerScope( infix fun andThenThrows(ex: Throwable) = andThenAnswer(ThrowingAnswer(ex)) + infix fun andThenThrowsMany(exList: List) = + andThenAnswer(ManyAnswersAnswer(exList.map { ThrowingAnswer(it) })) + @Deprecated("Use andThenAnswer instead of andThen.") infix fun andThen(answer: MockKAnswerScope.(Call) -> T) = andThenAnswer(FunctionAnswer { MockKAnswerScope(lambda, it).answer(it) }) diff --git a/modules/mockk/src/commonTest/kotlin/io/mockk/it/AdditionalAnswerTest.kt b/modules/mockk/src/commonTest/kotlin/io/mockk/it/AdditionalAnswerTest.kt index 7dbf0b52b..7898706b8 100644 --- a/modules/mockk/src/commonTest/kotlin/io/mockk/it/AdditionalAnswerTest.kt +++ b/modules/mockk/src/commonTest/kotlin/io/mockk/it/AdditionalAnswerTest.kt @@ -123,6 +123,53 @@ class AdditionalAnswerTest { } } + @Test + fun andThrowsMany() { + val exceptions = listOf( + IllegalArgumentException("error1"), + NullPointerException("error2"), + NoSuchElementException("error3") + ) + + every { mock.op(any()) } throwsMany exceptions + + assertFailsWith(IllegalArgumentException::class) { + mock.op(2) + } + assertFailsWith(NullPointerException::class) { + mock.op(3) + } + assertFailsWith(NoSuchElementException::class) { + mock.op(3) + } + assertFailsWith(NoSuchElementException::class) { + mock.op(4) + } + } + + @Test + fun andThenThrowsMany() { + val exceptions = listOf( + IllegalArgumentException("error1"), + NullPointerException("error2"), + NoSuchElementException("error3") + ) + every { mock.op(any()) } returns 3 andThenThrowsMany exceptions andThen 2 + + assertEquals(3, mock.op(1)) + assertFailsWith(IllegalArgumentException::class) { + mock.op(2) + } + assertFailsWith(NullPointerException::class) { + mock.op(3) + } + assertFailsWith(NoSuchElementException::class) { + mock.op(3) + } + assertEquals(2, mock.op(4)) + assertEquals(2, mock.op(5)) + } + @Test fun arbitraryLengthCheck() { every {