Mockito with Groovy fails to create stubs for partial mock for abstract class derivative
See original GitHub issueI 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 fromabstract
AbstractBase
parent. -
I am stubbing partial mock (
spy
) usingdoXxx
methods. -
=> failure
-
For contrast, the above steps are repeated with
Success
which is derived from regularBase
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:
- Created 6 years ago
- Comments:10 (3 by maintainers)
Top 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 >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
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
Broken Test Class
Successful Test Class
We have a bunch of dynamic class loading happening, can’t use
@CompileStatic
at the moment. Any possibility of a different workaround?