diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt index 72ceb6af..4897ec27 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt @@ -64,15 +64,31 @@ inline fun createInstance() = createInstance(T::class) @Suppress("UNCHECKED_CAST") fun createInstance(kClass: KClass): T { + var cause: Throwable? = null return MockitoKotlin.instanceCreator(kClass)?.invoke() as T? ?: - when { - kClass.hasObjectInstance() -> kClass.objectInstance!! - kClass.isPrimitive() -> kClass.toDefaultPrimitiveValue() - kClass.isMockable() -> kClass.java.uncheckedMock() - kClass.isEnum() -> kClass.java.enumConstants.first() - kClass.isArray() -> kClass.toArrayInstance() - kClass.isClassObject() -> kClass.toClassObject() - else -> kClass.easiestConstructor().newInstance() + try { + when { + kClass.hasObjectInstance() -> kClass.objectInstance!! + kClass.isPrimitive() -> kClass.toDefaultPrimitiveValue() + kClass.isEnum() -> kClass.java.enumConstants.first() + kClass.isArray() -> kClass.toArrayInstance() + kClass.isClassObject() -> kClass.toClassObject() + kClass.isMockable() -> try { + kClass.java.uncheckedMock() + } catch(e: Throwable) { + cause = e + kClass.easiestConstructor().newInstance() + } + else -> kClass.easiestConstructor().newInstance() + } + } catch(e: Exception) { + if (e is MockitoKotlinException) throw e + + cause?.let { + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + (e as java.lang.Throwable).initCause(it) + } + throw MockitoKotlinException("Could not create an instance for $kClass.", e) } } 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 0b326997..fc698255 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 @@ -94,7 +94,7 @@ inline fun mock(stubbing: KStubbing.(T) -> Unit): T { class KStubbing(private val mock: T) { fun on(methodCall: R) = Mockito.`when`(methodCall) - fun on(methodCall: T.() -> R, c: KClass): OngoingStubbing { + fun onGeneric(methodCall: T.() -> R, c: KClass): OngoingStubbing { val r = try { mock.methodCall() } catch(e: NullPointerException) { @@ -108,8 +108,16 @@ class KStubbing(private val mock: T) { return Mockito.`when`(r) } - inline fun on(noinline methodCall: T.() -> R): OngoingStubbing { - return on(methodCall, R::class) + inline fun onGeneric(noinline methodCall: T.() -> R): OngoingStubbing { + return onGeneric(methodCall, R::class) + } + + fun on(methodCall: T.() -> R): OngoingStubbing { + return try { + Mockito.`when`(mock.methodCall()) + } catch(e: NullPointerException) { + throw MockitoKotlinException("NullPointerException thrown when stubbing. If you are trying to stub a generic method, try `onGeneric` instead.", e) + } } } diff --git a/mockito-kotlin/src/test/kotlin/Classes.kt b/mockito-kotlin/src/test/kotlin/Classes.kt index faa67453..71923006 100644 --- a/mockito-kotlin/src/test/kotlin/Classes.kt +++ b/mockito-kotlin/src/test/kotlin/Classes.kt @@ -54,6 +54,7 @@ interface Methods { fun nullableString(s: String?) fun stringResult(): String + fun nullableStringResult(): String? fun builderMethod(): Methods } diff --git a/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt b/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt index 991bf735..2fc7e657 100644 --- a/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt +++ b/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt @@ -476,6 +476,24 @@ class CreateInstanceTest { expect(result.second).toBe(2) } + @Test + fun sealedClass() { + /* When */ + val result = createInstance(MySealedClass::class) + + /* Then */ + expect(result).toNotBeNull() + } + + @Test + fun sealedClassMember() { + /* When */ + val result = createInstance(MySealedClass.MySealedClassMember::class) + + /* Then */ + expect(result).toNotBeNull() + } + private class PrivateClass private constructor(val data: String) class ClosedClass @@ -537,4 +555,8 @@ class CreateInstanceTest { } enum class MyEnum { VALUE, ANOTHER_VALUE } + + sealed class MySealedClass { + class MySealedClassMember : MySealedClass() + } } diff --git a/mockito-kotlin/src/test/kotlin/MockitoTest.kt b/mockito-kotlin/src/test/kotlin/MockitoTest.kt index 3db6f1b8..b32355f1 100644 --- a/mockito-kotlin/src/test/kotlin/MockitoTest.kt +++ b/mockito-kotlin/src/test/kotlin/MockitoTest.kt @@ -351,6 +351,20 @@ class MockitoTest { expect(result).toBeTheSameAs(mock) } + @Test + fun testMockStubbing_nullable() { + /* Given */ + val mock = mock { + on { nullableStringResult() } doReturn "Test" + } + + /* When */ + val result = mock.nullableStringResult() + + /* Then */ + expect(result).toBe("Test") + } + @Test fun testMockStubbing_doThrow() { /* Given */ @@ -438,10 +452,22 @@ class MockitoTest { } @Test - fun doReturn_withGenericIntReturnType() { + fun doReturn_withGenericIntReturnType_on() { + /* Expect */ + expectErrorWithMessage("onGeneric") on { + + /* When */ + mock> { + on { genericMethod() } doReturn 2 + } + } + } + + @Test + fun doReturn_withGenericIntReturnType_onGeneric() { /* Given */ val mock = mock> { - on { genericMethod() } doReturn 2 + onGeneric { genericMethod() } doReturn 2 } /* Then */ diff --git a/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt b/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt index 47e35211..e7cf038a 100644 --- a/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt +++ b/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt @@ -23,6 +23,7 @@ */ import com.nhaarman.expect.expect +import com.nhaarman.expect.expectErrorWithMessage import com.nhaarman.mockito_kotlin.* import org.junit.Test import java.io.IOException @@ -105,7 +106,7 @@ class CreateInstanceInlineTest { /* Then */ expect(i).toBe(0) } - + @Test fun createStringInstance() { /* When */ @@ -115,10 +116,33 @@ class CreateInstanceInlineTest { expect(s).toBe("") } + @Test + fun sealedClass_fails() { + /* Expect */ + expectErrorWithMessage("Could not create") on { + + /* When */ + createInstance(MySealedClass::class) + } + } + + @Test + fun sealedClassMember() { + /* When */ + val result = createInstance(MySealedClass.MySealedClassMember::class) + + /* Then */ + expect(result).toNotBeNull() + } + interface Methods { fun throwableClass(t: ThrowableClass) } class ThrowableClass(cause: Throwable) : Throwable(cause) + + sealed class MySealedClass { + class MySealedClassMember : MySealedClass() + } }