mockito / mockito-kotlin

Using Mockito with Kotlin
MIT License
3.11k stars 201 forks source link

Typing whenever leads to "must not be null" #316

Closed reubenfirmin closed 5 years ago

reubenfirmin commented 5 years ago

This code works:

        val mockDownload = mock<Future<Long>>()
        whenever(mockDownload.get()).thenReturn(10L)

This code fails:

        val mockDownload = mock<Future<Long>>()
        whenever<Long>(mockDownload.get()).thenReturn(10L)

...with the error:

java.lang.IllegalStateException: mockDownload.get() must not be null

Obviously the type is superfluous; however, when converting a java codebase to kotlin (and mockito to mockito-kotlin) the type is often in place already.

nhaarman commented 5 years ago

This is because of the way the Kotlin compiler works, and how Mockito returns null for unstubbed methods.

The line whenever(mockDownload.get()) is essentially the same as

val long : Long! = mockDownload.get()
whenever(long)

where the result of mockDownload.get() has a platform type. By explicitly defining the Long type, you're informing the constructor of the non-nullability of the value, leading to an extra null check in the generated byte code:

Future mockDownload = (Future)var10000;
var10000 = mockDownload.get();
Intrinsics.checkExpressionValueIsNotNull(var10000, "mockDownload.get()");
Object methodCall$iv = var10000;
OngoingStubbing var15 = Mockito.when(methodCall$iv);

So this is not something the library can solve, unfortunately.