Kotlin JUnit Mockito


#1

Hello!

I have a problem with one unit test in kotlin.

I wrote tests in Kotlin and in Java, java test works nice, but kotlin test fails.


Java unit test:

 
@Test
public void createShouldCreateProposal() {
    //given
    Customer customer = new CustomerBuilder().build();
    ProposalDto proposalDto = new ProposalDto();
    proposalDto.setText("proposal text");
    when(customerService.getCurrentCustomer()).thenReturn(customer);
    when(proposalRepository.create(any(Proposal.class))).then(returnsFirstArg());

    //when
    Proposal actualProposal = service.create(proposalDto);

    //then
    assertNotNull(actualProposal);
    assertEquals("proposal text", actualProposal.getText());
    assertEquals(customer, actualProposal.getAuthor());
    assertEquals(false, actualProposal.getIsVerified());
}

Kotlin unit test:

Test
public fun createShouldCreateProposal() {
    //given
    val customer = CustomerBuilder().build()
    val proposalDto = ProposalDto()
    proposalDto.text = "proposal text"
    `when`(customerService!!.getCurrentCustomer()).thenReturn(customer)
    `when`(proposalRepository!!.create(any(javaClass<Proposal>())!!))!!.then(returnsFirstArg<Proposal>())

  //when
  val actualProposal = service.create(proposalDto)

  //then
  assertNotNull(actualProposal)
  assertEquals(“proposal text”, actualProposal.text)
  assertEquals(customer, actualProposal.author)
  assertEquals(false, actualProposal.isVerified)
}

Stacktrice:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced argument matcher detected here:

-> at org.anygoods.core.service.ProposalServiceImplUnitTest.createShouldCreateProposal(ProposalServiceImplUnitTest.kt:72)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

     at org.mockito.internal.runners.util.FrameworkUsageValidator.testFinished(FrameworkUsageValidator.java:25)
     at org.junit.runner.notification.RunNotifier$7.notifyListener(RunNotifier.java:191)
     at org.junit.runner.notification.RunNotifier$SafeNotifier.run(RunNotifier.java:61)
     at org.junit.runner.notification.RunNotifier.fireTestFinished(RunNotifier.java:188)
     at org.junit.internal.runners.model.EachTestNotifier.fireTestFinished(EachTestNotifier.java:39)
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:277)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
     at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
     at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
     at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
     at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
     at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
     at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
     at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:606)
     at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
     at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
     at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
     at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
     at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
     at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:606)
     at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
     at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
     at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
     at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
     at java.lang.Thread.run(Thread.java:745)

Have any idea?


#2
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().

... and in Kotlin classes and members are final by default, we need to open them. Don't know if that is the case.


#3

The proposalRepository is a trait, problem only with any()

works:

when(proposalRepository!!.update(proposal)).then(object : Answer<Proposal> {
  override fun answer(invocation: InvocationOnMock?): Proposal {
  return invocation!!.getArguments()[0] as Proposal
  }
})

fails:

when(proposalRepository!!. update(any(javaClass<Proposal>())!!))!!.then(object : Answer<Proposal> {
  override fun answer(invocation: InvocationOnMock?): Proposal {
  return invocation!!.getArguments()[0] as Proposal
  }
})

I marked update method as “open”, but it didn’t help.


#4

Additional question: what approache should I use to test my kotlin classes if I don't want make its opened only for testing?


#5

Any update on this?