From f9f3abc42dd55a991ffa2699f8d0987a68947d90 Mon Sep 17 00:00:00 2001 From: Niek Haarman Date: Thu, 19 Jan 2017 22:20:06 +0100 Subject: [PATCH 1/2] Add regression tests in preparation for settings API --- .../src/test/kotlin/test/Classes.kt | 11 ++ .../src/test/kotlin/test/MockitoTest.kt | 165 +++++++++++++++++- 2 files changed, 174 insertions(+), 2 deletions(-) diff --git a/mockito-kotlin/src/test/kotlin/test/Classes.kt b/mockito-kotlin/src/test/kotlin/test/Classes.kt index 58dc9958..3476585c 100644 --- a/mockito-kotlin/src/test/kotlin/test/Classes.kt +++ b/mockito-kotlin/src/test/kotlin/test/Classes.kt @@ -60,6 +60,17 @@ interface Methods { fun stringResult(s: String): String fun nullableStringResult(): String? fun builderMethod(): Methods + + fun nonDefaultReturnType(): ExtraInterface +} + +interface ExtraInterface + +abstract class ThrowingConstructor { + + constructor() { + error("Error in constructor") + } } interface GenericMethods { diff --git a/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt b/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt index 65670f2c..ace45f92 100644 --- a/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt +++ b/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt @@ -5,8 +5,15 @@ import com.nhaarman.expect.expectErrorWithMessage import com.nhaarman.expect.fail import com.nhaarman.mockito_kotlin.* import org.junit.Test +import org.mockito.Mockito import org.mockito.exceptions.base.MockitoAssertionError +import org.mockito.exceptions.verification.WantedButNotInvoked +import org.mockito.listeners.InvocationListener +import org.mockito.mock.SerializableMode.BASIC import java.io.IOException +import java.io.PrintStream +import java.io.Serializable + /* * The MIT License @@ -244,8 +251,8 @@ class MockitoTest : TestBase() { val mock = mock() doAnswer { "Test" } - .whenever(mock) - .stringResult() + .whenever(mock) + .stringResult() expect(mock.stringResult()).toBe("Test") } @@ -479,6 +486,160 @@ class MockitoTest : TestBase() { } } + @Test + fun mock_withCustomName() { + /* Given */ + val mock = mock("myName") + + /* Expect */ + expectErrorWithMessage("myName.stringResult()") on { + verify(mock).stringResult() + } + } + + @Test + fun mock_withCustomDefaultAnswer() { + /* Given */ + val mock = mock(Mockito.RETURNS_SELF) + + /* When */ + val result = mock.builderMethod() + + /* Then */ + expect(result).toBe(mock) + } + + @Test + fun mock_withCustomDefaultAnswer_parameterName() { + /* Given */ + val mock = mock(defaultAnswer = Mockito.RETURNS_SELF) + + /* When */ + val result = mock.builderMethod() + + /* Then */ + expect(result).toBe(mock) + } + + @Test + fun mock_withSettings_extraInterfaces() { + /* Given */ + val mock = mock( + withSettings().extraInterfaces(ExtraInterface::class.java) + ) + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mock_withSettings_name() { + /* Given */ + val mock = mock( + withSettings().name("myName") + ) + + /* When */ + expectErrorWithMessage("myName.stringResult()") on { + verify(mock).stringResult() + } + } + + @Test + fun mock_withSettings_defaultAnswer() { + /* Given */ + val mock = mock( + withSettings().defaultAnswer(Mockito.RETURNS_MOCKS) + ) + + /* When */ + val result = mock.nonDefaultReturnType() + + /* Then */ + expect(result).toNotBeNull() + } + + @Test + fun mock_withSettings_serializable() { + /* Given */ + val mock = mock( + withSettings().serializable() + ) + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mock_withSettings_serializableMode() { + /* Given */ + val mock = mock( + withSettings().serializable(BASIC) + ) + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mock_withSettings_verboseLogging() { + /* Given */ + val out = mock() + System.setOut(out) + val mock = mock( + withSettings().verboseLogging() + ) + + try { + /* When */ + verify(mock).stringResult() + fail("Expected an exception") + } catch(e: WantedButNotInvoked) { + /* Then */ + verify(out).println("methods.stringResult();") + } + } + + @Test + fun mock_withSettings_invocationListeners() { + /* Given */ + var bool = false + val mock = mock( + withSettings().invocationListeners(InvocationListener { bool = true }) + ) + + /* When */ + mock.stringResult() + + /* Then */ + expect(bool).toHold() + } + + @Test + fun mock_withSettings_stubOnly() { + /* Given */ + val mock = mock( + withSettings().stubOnly() + ) + + /* Expect */ + expectErrorWithMessage("is a stubOnly() mock") on { + + /* When */ + verify(mock).stringResult() + } + } + + @Test + fun mock_withSettings_useConstructor() { + /* Expect */ + expectErrorWithMessage("Unable to create mock instance of type") on { + mock( + withSettings().useConstructor() + ) + } + } + @Test fun stubbingTwiceWithArgumentMatchers() { /* When */ From 26a139fdffab393cd470a3ebaad00660edf89990 Mon Sep 17 00:00:00 2001 From: Niek Haarman Date: Thu, 19 Jan 2017 21:14:17 +0100 Subject: [PATCH 2/2] Enhance settings API --- .../com/nhaarman/mockito_kotlin/Mockito.kt | 109 +++++++-- .../src/test/kotlin/test/MockitoTest.kt | 216 +++++++++++++++++- 2 files changed, 305 insertions(+), 20 deletions(-) diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt index c64a5141..379d2186 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt @@ -26,16 +26,16 @@ package com.nhaarman.mockito_kotlin import com.nhaarman.mockito_kotlin.createinstance.createInstance -import org.mockito.InOrder -import org.mockito.MockSettings -import org.mockito.MockingDetails -import org.mockito.Mockito +import org.mockito.* import org.mockito.invocation.InvocationOnMock +import org.mockito.listeners.InvocationListener +import org.mockito.mock.SerializableMode import org.mockito.stubbing.Answer import org.mockito.stubbing.OngoingStubbing import org.mockito.stubbing.Stubber import org.mockito.verification.VerificationMode import org.mockito.verification.VerificationWithTimeout +import kotlin.DeprecationLevel.WARNING import kotlin.reflect.KClass fun after(millis: Long) = Mockito.after(millis) @@ -74,7 +74,7 @@ inline fun argForWhich(noinline predicate: T.() -> Boolean) = * * @param predicate A function that returns `true` when given [T] matches the predicate. */ -inline fun argWhere(noinline predicate: (T) -> Boolean) = argThat(predicate) +inline fun argWhere(noinline predicate: (T) -> Boolean) = argThat(predicate) /** * For usage with verification only. @@ -120,16 +120,70 @@ inline fun isA(): T = Mockito.isA(T::class.java) ?: createInst fun isNotNull(): T? = Mockito.isNotNull() fun isNull(): T? = Mockito.isNull() -inline fun mock(): T = Mockito.mock(T::class.java)!! -inline fun mock(defaultAnswer: Answer): T = Mockito.mock(T::class.java, defaultAnswer)!! +inline fun mock( + extraInterfaces: Array>? = null, + name: String? = null, + spiedInstance: Any? = null, + defaultAnswer: Answer? = null, + serializable: Boolean = false, + serializableMode: SerializableMode? = null, + verboseLogging: Boolean = false, + invocationListeners: Array? = null, + stubOnly: Boolean = false, + @Incubating useConstructor: Boolean = false, + @Incubating outerInstance: Any? = null +): T = Mockito.mock(T::class.java, withSettings( + extraInterfaces = extraInterfaces, + name = name, + spiedInstance = spiedInstance, + defaultAnswer = defaultAnswer, + serializable = serializable, + serializableMode = serializableMode, + verboseLogging = verboseLogging, + invocationListeners = invocationListeners, + stubOnly = stubOnly, + useConstructor = useConstructor, + outerInstance = outerInstance +))!! + +inline fun mock( + extraInterfaces: Array>? = null, + name: String? = null, + spiedInstance: Any? = null, + defaultAnswer: Answer? = null, + serializable: Boolean = false, + serializableMode: SerializableMode? = null, + verboseLogging: Boolean = false, + invocationListeners: Array? = null, + stubOnly: Boolean = false, + @Incubating useConstructor: Boolean = false, + @Incubating outerInstance: Any? = null, + stubbing: KStubbing.(T) -> Unit +): T = Mockito.mock(T::class.java, withSettings( + extraInterfaces = extraInterfaces, + name = name, + spiedInstance = spiedInstance, + defaultAnswer = defaultAnswer, + serializable = serializable, + serializableMode = serializableMode, + verboseLogging = verboseLogging, + invocationListeners = invocationListeners, + stubOnly = stubOnly, + useConstructor = useConstructor, + outerInstance = outerInstance +)).apply { + KStubbing(this).stubbing(this) +}!! + +@Deprecated("Use mock() with optional arguments instead.", ReplaceWith("mock(defaultAnswer = a)"), level = WARNING) +inline fun mock(a: Answer): T = mock(defaultAnswer = a) + +@Deprecated("Use mock() with optional arguments instead.", ReplaceWith("mock(name = s)"), level = WARNING) +inline fun mock(s: String): T = mock(name = s) + +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated("Use mock() with optional arguments instead.", level = WARNING) inline fun mock(s: MockSettings): T = Mockito.mock(T::class.java, s)!! -inline fun mock(s: String): T = Mockito.mock(T::class.java, s)!! - -inline fun mock(stubbing: KStubbing.(T) -> Unit): T { - return mock().apply { - KStubbing(this).stubbing(this) - } -} class KStubbing(private val mock: T) { fun on(methodCall: R) = Mockito.`when`(methodCall) @@ -193,4 +247,29 @@ fun verifyNoMoreInteractions(vararg mocks: T) = Mockito.verifyNoMoreInteract fun verifyZeroInteractions(vararg mocks: Any) = Mockito.verifyZeroInteractions(*mocks) fun whenever(methodCall: T): OngoingStubbing = Mockito.`when`(methodCall)!! -fun withSettings(): MockSettings = Mockito.withSettings()!! + +fun withSettings( + extraInterfaces: Array>? = null, + name: String? = null, + spiedInstance: Any? = null, + defaultAnswer: Answer? = null, + serializable: Boolean = false, + serializableMode: SerializableMode? = null, + verboseLogging: Boolean = false, + invocationListeners: Array? = null, + stubOnly: Boolean = false, + @Incubating useConstructor: Boolean = false, + @Incubating outerInstance: Any? = null +): MockSettings = Mockito.withSettings().apply { + extraInterfaces?.let { extraInterfaces(*it.map { it.java }.toTypedArray()) } + name?.let { name(it) } + spiedInstance?.let { spiedInstance(it) } + defaultAnswer?.let { defaultAnswer(it) } + if (serializable) serializable() + serializableMode?.let { serializable(it) } + if (verboseLogging) verboseLogging() + invocationListeners?.let { invocationListeners(*it) } + if (stubOnly) stubOnly() + if (useConstructor) useConstructor() + outerInstance?.let { outerInstance(it) } +} diff --git a/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt b/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt index ace45f92..ce57d620 100644 --- a/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt +++ b/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt @@ -6,6 +6,7 @@ import com.nhaarman.expect.fail import com.nhaarman.mockito_kotlin.* import org.junit.Test import org.mockito.Mockito +import org.mockito.Mockito.RETURNS_MOCKS import org.mockito.exceptions.base.MockitoAssertionError import org.mockito.exceptions.verification.WantedButNotInvoked import org.mockito.listeners.InvocationListener @@ -40,6 +41,7 @@ import java.io.Serializable * THE SOFTWARE. */ +@Suppress("DEPRECATION") class MockitoTest : TestBase() { @Test @@ -415,7 +417,7 @@ class MockitoTest : TestBase() { @Test fun testMockStubbing_doThrow() { /* Given */ - val mock = mock { mock -> + val mock = mock { on { builderMethod() } doThrow IllegalArgumentException() } @@ -430,7 +432,7 @@ class MockitoTest : TestBase() { @Test fun testMockStubbing_doThrowClass() { /* Given */ - val mock = mock { mock -> + val mock = mock { on { builderMethod() } doThrow IllegalArgumentException::class } @@ -445,7 +447,7 @@ class MockitoTest : TestBase() { @Test fun testMockStubbing_doThrowVarargs() { /* Given */ - val mock = mock { mock -> + val mock = mock { on { builderMethod() }.doThrow(IllegalArgumentException(), UnsupportedOperationException()) } @@ -467,7 +469,7 @@ class MockitoTest : TestBase() { @Test fun testMockStubbing_doThrowClassVarargs() { /* Given */ - val mock = mock { mock -> + val mock = mock { on { builderMethod() }.doThrow(IllegalArgumentException::class, UnsupportedOperationException::class) } @@ -549,7 +551,7 @@ class MockitoTest : TestBase() { fun mock_withSettings_defaultAnswer() { /* Given */ val mock = mock( - withSettings().defaultAnswer(Mockito.RETURNS_MOCKS) + withSettings().defaultAnswer(RETURNS_MOCKS) ) /* When */ @@ -640,6 +642,210 @@ class MockitoTest : TestBase() { } } + @Test + fun mock_withSettingsAPI_extraInterfaces() { + /* Given */ + val mock = mock( + extraInterfaces = arrayOf(ExtraInterface::class) + ) + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mock_withSettingsAPI_name() { + /* Given */ + val mock = mock(name = "myName") + + /* When */ + expectErrorWithMessage("myName.stringResult()") on { + verify(mock).stringResult() + } + } + + @Test + fun mock_withSettingsAPI_defaultAnswer() { + /* Given */ + val mock = mock(defaultAnswer = RETURNS_MOCKS) + + /* When */ + val result = mock.nonDefaultReturnType() + + /* Then */ + expect(result).toNotBeNull() + } + + @Test + fun mock_withSettingsAPI_serializable() { + /* Given */ + val mock = mock(serializable = true) + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mock_withSettingsAPI_serializableMode() { + /* Given */ + val mock = mock(serializableMode = BASIC) + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mock_withSettingsAPI_verboseLogging() { + /* Given */ + val out = mock() + System.setOut(out) + val mock = mock(verboseLogging = true) + + try { + /* When */ + verify(mock).stringResult() + fail("Expected an exception") + } catch(e: WantedButNotInvoked) { + /* Then */ + verify(out).println("methods.stringResult();") + } + } + + @Test + fun mock_withSettingsAPI_invocationListeners() { + /* Given */ + var bool = false + val mock = mock(invocationListeners = arrayOf(InvocationListener { bool = true })) + + /* When */ + mock.stringResult() + + /* Then */ + expect(bool).toHold() + } + + @Test + fun mock_withSettingsAPI_stubOnly() { + /* Given */ + val mock = mock(stubOnly = true) + + /* Expect */ + expectErrorWithMessage("is a stubOnly() mock") on { + + /* When */ + verify(mock).stringResult() + } + } + + @Test + fun mock_withSettingsAPI_useConstructor() { + /* Given */ + expectErrorWithMessage("Unable to create mock instance of type ") on { + mock(useConstructor = true) {} + } + } + + @Test + fun mockStubbing_withSettingsAPI_extraInterfaces() { + /* Given */ + val mock = mock(extraInterfaces = arrayOf(ExtraInterface::class)) {} + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mockStubbing_withSettingsAPI_name() { + /* Given */ + val mock = mock(name = "myName") {} + + /* When */ + expectErrorWithMessage("myName.stringResult()") on { + verify(mock).stringResult() + } + } + + @Test + fun mockStubbing_withSettingsAPI_defaultAnswer() { + /* Given */ + val mock = mock(defaultAnswer = RETURNS_MOCKS) {} + + /* When */ + val result = mock.nonDefaultReturnType() + + /* Then */ + expect(result).toNotBeNull() + } + + @Test + fun mockStubbing_withSettingsAPI_serializable() { + /* Given */ + val mock = mock(serializable = true) {} + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mockStubbing_withSettingsAPI_serializableMode() { + /* Given */ + val mock = mock(serializableMode = BASIC) {} + + /* Then */ + expect(mock).toBeInstanceOf() + } + + @Test + fun mockStubbing_withSettingsAPI_verboseLogging() { + /* Given */ + val out = mock() + System.setOut(out) + val mock = mock(verboseLogging = true) {} + + try { + /* When */ + verify(mock).stringResult() + fail("Expected an exception") + } catch(e: WantedButNotInvoked) { + /* Then */ + verify(out).println("methods.stringResult();") + } + } + + @Test + fun mockStubbing_withSettingsAPI_invocationListeners() { + /* Given */ + var bool = false + val mock = mock(invocationListeners = arrayOf(InvocationListener { bool = true })) {} + + /* When */ + mock.stringResult() + + /* Then */ + expect(bool).toHold() + } + + @Test + fun mockStubbing_withSettingsAPI_stubOnly() { + /* Given */ + val mock = mock(stubOnly = true) {} + + /* Expect */ + expectErrorWithMessage("is a stubOnly() mock") on { + + /* When */ + verify(mock).stringResult() + } + } + + @Test + fun mockStubbing_withSettingsAPI_useConstructor() { + /* Given */ + expectErrorWithMessage("Unable to create mock instance of type ") on { + mock(useConstructor = true) {} + } + } + @Test fun stubbingTwiceWithArgumentMatchers() { /* When */