jtanistra / spock

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

Cannot mock interfaces that have calls to static methods #227

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
When I'm trying to mock PsiElementFactory interface from Intellij Idea 
Community sources (from com.intellij.psi package) like this:
PsiElementFactory elementFactory = Mock()
I'm getting:
java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at org.spockframework.mock.DefaultMockFactory.createDynamicProxyMock(DefaultMockFactory.java:63)
    at org.spockframework.mock.DefaultMockFactory.create(DefaultMockFactory.java:52)
    at org.spockframework.mock.MockController.create(MockController.java:80)
    at spock.lang.Specification.Mock(Specification.java:244) 

This interface is a little bit unusual, and it probably causes the problem:
public interface PsiElementFactory extends PsiJavaParserFacade, 
JVMElementFactory {
  class SERVICE {
    private SERVICE() {
    }

    public static PsiElementFactory getInstance(Project project) {
      return ServiceManager.getService(project, PsiElementFactory.class);
    }
  }
(...)

I'm using spock-core:0.5-groovy-1.7. 

Original issue reported on code.google.com by m.jedy...@gmail.com on 7 Feb 2012 at 9:07

GoogleCodeExporter commented 8 years ago
I can't reproduce this. Using 0.6-groovy-1.7-SNAPSHOT, mocking the following 
interface works fine:

public interface InterfaceWithNestedClass {
  class Service {
    private Service() {}

    public static InterfaceWithNestedClass getInstance() {
      return null;
    }
  }
}

Does this work for you as well? If yes, can you provide a self-contained 
interface definition which can't be mocked?

Original comment by pnied...@gmail.com on 9 Feb 2012 at 12:44

GoogleCodeExporter commented 8 years ago
Your example works, because getInstance() doesn't do anything, the problem is 
that ServiceManager.getService(project, PsiElementFactory.class) is throwing an 
exception
when invoked in the test (outside IntelliJ context).

java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at org.spockframework.mock.DefaultMockFactory.createDynamicProxyMock(DefaultMockFactory.java:63)
    at org.spockframework.mock.DefaultMockFactory.create(DefaultMockFactory.java:52)
    at org.spockframework.mock.MockController.create(MockController.java:80)
    at spock.lang.Specification.Mock(Specification.java:244)
Caused by: java.lang.NullPointerException
    at com.intellij.openapi.components.ServiceManager.getService(ServiceManager.java:36)

Mockito is dealing with it without any problems.

Original comment by m.jedy...@gmail.com on 12 Feb 2012 at 7:51

GoogleCodeExporter commented 8 years ago
Could you please provide a self-contained example demonstrating the problem?

Original comment by pnied...@gmail.com on 12 Feb 2012 at 8:15

GoogleCodeExporter commented 8 years ago
Here it goes. You need to install IntelliJ Idea 11 and specify the installation 
dir in build.gradle. I couldn't attach Idea jars as they have >100MB.

Original comment by m.jedy...@gmail.com on 15 Feb 2012 at 7:50

Attachments:

GoogleCodeExporter commented 8 years ago
I was hoping for a small self-contained example, but thanks anyway. As "by: 
pniederw" in YouTrack will tell you, I'm already an IDEA (11) user. :-)

Original comment by pe...@gradle.biz on 16 Feb 2012 at 5:06

GoogleCodeExporter commented 8 years ago
This doesn't look like a Spock bug to me. When the mock is created, the 
PsiSubstitutor class happens to get initialized (which is referenced from 
PsiElementFactory), and a NPE occurs. Here is the stack trace:

Caused by: java.lang.NullPointerException
    at com.intellij.openapi.components.ServiceManager.getService(ServiceManager.java:36)
    at com.intellij.psi.EmptySubstitutor.getInstance(EmptySubstitutor.java:28)
    at com.intellij.psi.PsiSubstitutor.<clinit>(PsiSubstitutor.java:45)

For some reason, this only happens when a dynamic proxy is used for the mock, 
but not when CGLIB is used. This may be why it works with Mockito. Usually, 
Spock uses CGLIB only when mocking classes (as opposed to interfaces). One way 
out would be to make this configurable.

Original comment by pnied...@gmail.com on 12 May 2012 at 6:15

GoogleCodeExporter commented 8 years ago
I invested serious time into this but couldn't find the cause. Forcing the use 
of CGLIB didn't solve the problem. I found it hard to reproduce this problem 
outside the IDEA codebase. (Unfortunately I don't remember if I eventually 
succeeded.) If this is still a critical problem for you, please open another 
issue.

Original comment by pnied...@gmail.com on 4 Oct 2012 at 7:21