Convert Java Mockito test to Kotlin

Viewed 985

I've got an issue converting the following working Java test to Kotlin

@Test
public void testSomething() {

    Mockito.when(parkIdMappingRepository.save(Mockito.any(ParkIdMapping.class))).thenAnswer(
        (Answer<ParkIdMapping>) invocation -> {
            ParkIdMapping mapping = invocation.getArgument(0);
            mapping.setId(100L);
            return mapping;
        }
    );
    ParkIdMapping mapping = parkIdMappingRepository.save(new ParkIdMapping("123"));

    assertEquals(new Long(100L), mapping.getId());

The conversion done by Intellij Idea to Kotlin results in:

@Test
public fun test_correctParkIdMappingGeneration() {

    Mockito.`when`(parkIdMappingRepository.save(Mockito.any(ParkIdMapping::class.java))).thenAnswer(
        { invocation -> // compiler error
            val mapping = invocation.getArgument(0)
            mapping.id = 100L
            mapping
        } as Answer<ParkIdMapping>
    )
    val mapping = parkIdMappingRepository.save(ParkIdMapping("123"))

    assertEquals(100L, mapping.id)
}

The line with the lambda parameter 'invocation', however, causes a compiler error:

Cannot infer a type for this parameter. Please specify it explicitly .

I've tried to adjust the lambda like this

    Mockito.`when`(parkIdMappingRepository.save(Mockito.any(ParkIdMapping::class.java))).thenAnswer(
        { invocation: InvocationOnMock ->
            val mapping = invocation.getArgument(0) as ParkIdMapping
            mapping.id = 100L
            mapping
        } as Answer<ParkIdMapping>
    )

resulting in

java.lang.ClassCastException: com.foobar.ParkIdGenerationServiceTest$test_correctParkIdMappingGeneration$1 cannot be cast to org.mockito.stubbing.Answer

org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at com.foobar.ParkIdGenerationServiceTest.testSomething(ParkIdGenerationServiceTest.kt:92)

The original intent is to modify the entity that is passed to the save method of the repository and return it. Any ideas what to do?

1 Answers

Move unchecked cast to Answer<ParkIdMapping> to getArgument call.

Also, you need to add helper mock method. Mockito.any() returns null in it's verification function and the mock throws NPE because of Kotlin Null-safety feature.

Like this:

fun <T> any(): T {
    Mockito.any<T>()
    return uninitialized()
}

fun <T> uninitialized(): T = null as T

And the test will be:

@Test
public fun test_correctParkIdMappingGeneration() {

    Mockito.`when`<ParkIdMapping>(parkIdMappingRepository.save(any())).thenAnswer(
        { invocation -> // compiler error
            val mapping = invocation.getArgument<ParkIdMapping>(0)
            mapping.id = 100L
            mapping
        }
    )
    val mapping = parkIdMappingRepository.save(ParkIdMapping("123"))

    assertEquals(100L, mapping.id)
}

Future reading on Kotlin and Mockito interop: https://medium.com/@elye.project/befriending-kotlin-and-mockito-1c2e7b0ef791

Related