joepadde / mockito

Automatically exported from code.google.com/p/mockito
0 stars 0 forks source link

Error when calling method on spy that extends interface with default method in JDK 8 #456

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Mockito version: 1.9.5

Java version :

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 
1.8.0-ea-lambda-nightly-h109-20130902-b106 b00)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b45, mixed mode)

on Windows 7

---EXAMPLE-----

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.spy;

public class Mockito_Spy_Failure_JDK8
{
    @Test
    public void fails() throws Exception
    {
        Failure spy = spy(new Failure());

        assertEquals("done", spy.do_something() );
    }

    interface Complete
    {
        public default String do_something()
        {
            return "done";
        }
    }

    static class Failure implements Complete
    {

    }
}

------------OUTPUT (Intellij IDEA)--------------

org.mockito.exceptions.base.MockitoException: 
Cannot call real method on java interface. Interface does not have any 
implementation!
Calling real methods is only possible when mocking concrete classes.
  //correct example:
  when(mockOfConcreteClass.doStuff()).thenCallRealMethod();
    at Mockito_Spy_Failure_JDK8.fails(Mockito_Spy_Failure_JDK8.java:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    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.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Original issue reported on code.google.com by Jose.Llarena@gmail.com on 11 Oct 2013 at 10:24

GoogleCodeExporter commented 8 years ago
Interesting, I could have the chance to try mockito on JDK8 yet

Original comment by brice.du...@gmail.com on 4 Dec 2013 at 2:08

GoogleCodeExporter commented 8 years ago
Yeah, we need to make Mockito working with java 1.8 which is due March 2014.

Original comment by szcze...@gmail.com on 19 Jan 2014 at 9:03

GoogleCodeExporter commented 8 years ago
Indeed, just to emphasise that this problem is actually more of a showstopper 
than it might sound because many classes in a Java 8 codebase will directly or 
indirectly implement an interface with default methods

Original comment by Jose.Llarena@gmail.com on 20 Jan 2014 at 10:49

GoogleCodeExporter commented 8 years ago
Don't forget that in mocking theory you shouldn't type you don't own, which is 
usually a golden rule for several reasons beyond Java 8 ;)

Nevertheless I agree the whole Java community needs to work on a new proxy lib, 
spring, hibernate, achilles, ejb containes, hikaricp, etc... will need a new 
proxy lib.

Original comment by brice.du...@gmail.com on 22 Jan 2014 at 5:48

GoogleCodeExporter commented 8 years ago
Hmm, this particular issue might be easy to solve. Jose, can you build Mockito 
with one little modification and try it out? You could remove the "Cannot call 
real method on java interface" check as this is something that lives in our 
code. Not sure how exactly default methods are implemented but maybe cglib will 
deal with this.

Original comment by szcze...@gmail.com on 27 Jan 2014 at 8:59

GoogleCodeExporter commented 8 years ago
"Cannot call real method on java interface" check reside in mockito:
InvocationImpl#callRealMethod
AnswersValidator#validateMockingConcreteClass

if (methodInfo.isDeclaredOnInterface()) {
     reporter.cannotCallRealMethodOnInterface();
}

JDK 8 add "isDefault" operation to the Method class that checks if method is:
- declared in an interface
- public
- not abstract
- not static (instance)

I think that we should not only checking (at mentioned places) whether method 
is declared in interface but also whether it is not default.

Original comment by albers...@gmail.com on 24 Feb 2014 at 11:07

GoogleCodeExporter commented 8 years ago
Interesting. However if we add this check mockito won't compile anymore on 
previous version of the JDK right ?

Original comment by brice.du...@gmail.com on 4 Mar 2014 at 9:02

GoogleCodeExporter commented 8 years ago
I think that the best idea will be not to used isDefaultMethod provided in jdk8 
but use mentioned checks

Original comment by albers...@gmail.com on 4 Mar 2014 at 10:19

GoogleCodeExporter commented 8 years ago
I like this idea, but the code should be self explanotry on this one :)

Original comment by brice.du...@gmail.com on 4 Mar 2014 at 11:10

GoogleCodeExporter commented 8 years ago
So this is the single biggest issue blocking my team from Java-8 gents, I would 
really appreciate a fix :(

Original comment by Groostav on 3 Jun 2014 at 6:10

GoogleCodeExporter commented 8 years ago
@Groostav did you tried our latest snapshots, with the help of another talented 
dev we have tackled this issue while keeping the code compilable from Java 5 ?

You may have to build from source though.

Original comment by brice.du...@gmail.com on 27 Jun 2014 at 4:03

GoogleCodeExporter commented 8 years ago

Original comment by szcze...@gmail.com on 24 Aug 2014 at 3:13

GoogleCodeExporter commented 8 years ago

Original comment by szcze...@gmail.com on 24 Aug 2014 at 3:50