question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Mockito with Groovy fails to create stubs for partial mock for abstract class derivative

See original GitHub issue

I am using Mockito 2.8.9 with Groovy 2.4.1 and JUnit 4.12 (openjdk version “1.8.0_131”)

The setup:

  • I have an instance of the Failure class that is derived from abstract AbstractBase parent.

  • I am stubbing partial mock (spy) using doXxx methods.

  • => failure

  • For contrast, the above steps are repeated with Success which is derived from regular Base parent.

  • => success

The tests:

import org.junit.Test
import static org.mockito.Mockito.*

abstract class AbstractBase { }

class Failure extends AbstractBase {
    def method() { }
}

class Base { }

class Success extends Base {
    def method() { }
}

class FooTest {
    @Test
    void failed() {
        def sut = spy(new Failure())
        doReturn(1).when(sut).method()
    }

    @Test
    void succeed() {
        def sut = spy(new Success())
        doReturn(1).when(sut).method()
    }
}

As test names suggest, succeed() works as expected, while failed() generates an error with following message and stack trace (integer is incidental, I verified with several types):


org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Integer cannot be returned by getMetaClass()
getMetaClass() should return MetaClass
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
   Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - 
   - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.


	at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPogoSite(CallSiteArray.java:147)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:164)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
	at FooTest.failed(FooTest.groovy:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Thank you!

P.S. I ran it also with Groovy 2.4.10, and with Mockito 2.7.22 – with the same result

Issue Analytics

  • State:open
  • Created 6 years ago
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
agabryscommented, Oct 19, 2020

I found a working workaround. It requires some code changes, but only in tests. You can add the groovy.transform.CompileStatic annotation to the test class. I checked if for the above example.

Sources

package issue1108

abstract class DAO {}
package issue1108

class Person {}
package issue1108

class PersonDAO extends DAO {

	Person findById(Long id) {
		return new Person()
	}
}

Broken Test Class

package issue1108

import static org.junit.jupiter.api.Assertions.assertNotNull
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.when

import org.junit.jupiter.api.Test
import org.mockito.Mockito

class PersonDAOTest extends DAO {

	@Test
	void fails() {
		def dao = mock(PersonDAO)
		when(dao.findById(Mockito.anyLong())).thenReturn(new Person())
		def person = dao.findById(1L)
		assertNotNull(person)
	}
}

failure

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

	at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPogoSite(CallSiteArray.java:146)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:163)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
	at issue1108.PersonDAOTest.fails(PersonDAOTest.groovy:15)
	[...]

Successful Test Class

package issue1108

import static org.junit.jupiter.api.Assertions.assertNotNull
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.when

import groovy.transform.CompileStatic
import org.junit.jupiter.api.Test
import org.mockito.Mockito

@CompileStatic
class PersonDAOTest extends DAO {

	@Test
	void fails() {
		def dao = mock(PersonDAO)
		when(dao.findById(Mockito.anyLong())).thenReturn(new Person())
		def person = dao.findById(1L)
		assertNotNull(person)
	}
}

success

0reactions
solvingjcommented, Dec 12, 2022

We have a bunch of dynamic class loading happening, can’t use @CompileStatic at the moment. Any possibility of a different workaround?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Mockito to test abstract classes - java - Stack Overflow
The following suggestion let's you test abstract classes without creating a "real" subclass - the Mock is the subclass. use Mockito.mock(My.class, Mockito.
Read more >
Mockito Spying or Mocking Abstract Classes - Javatpoint
In this example, we are going to mock the abstract classes using the Mockito.mock() method. Usually, mocking is used to create a clone...
Read more >
Spock Framework Reference Documentation
Spock is a testing and specification framework for Java and Groovy applications. What makes it stand out from the crowd is its beautiful...
Read more >
Mocking only Abstract Methods using Mockito (Partial Mocking)
I remember back in the days, before any mocking frameworks existed in Java, we used to create an ano... by Naresh Jain.
Read more >
Spock测试框架官方参考文档
Combining Mocking and Stubbing; Other Kinds of Mock Objects. Stubs; Spies; Partial Mocks. Groovy Mocks. Mocking Dynamic Methods; Mocking All ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found