How to spy Java File with Spock 0.7?

1,892 views
Skip to first unread message

Marcin Gryszko

unread,
Oct 5, 2013, 5:09:47 PM10/5/13
to spockfr...@googlegroups.com
I'm not able to spy java.io.File. Following spec (working in Groovy console) demonstrates the exception I'm getting. It seems that the class to spyt must have a default constructor, does it?

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')

import spock.lang.Specification

class FileSpySpec extends Specification {
    def setup() {
        GroovySpy(File, global: true)
    }
    
    def 'file spy'() { 
        expect: true         
    }
}

Runtime exception:

org.spockframework.mock.CannotCreateMockException: Cannot create mock for class java.io.Filenull
at org.spockframework.mock.runtime.MockInstantiator.instantiate(MockInstantiator.java:38)
at org.spockframework.mock.runtime.GroovyMockFactory.create(GroovyMockFactory.java:54)
at org.spockframework.mock.runtime.CompositeMockFactory.create(CompositeMockFactory.java:44)
at org.spockframework.lang.SpecInternals.createMock(SpecInternals.java:47)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:282)
at org.spockframework.lang.SpecInternals.GroovySpyImpl(SpecInternals.java:267)
at FileSpySpec.setup(spec.groovy:7)
Caused by: org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
  public java.io.File#<init>(java.net.URI)
  private java.io.File#<init>(java.lang.String, int)
  private java.io.File#<init>(java.lang.String, java.io.File)
  public java.io.File#<init>(java.lang.String)
  public java.io.File#<init>(java.lang.String, java.lang.String)
  public java.io.File#<init>(java.io.File, java.lang.String)
at org.spockframework.mock.runtime.GroovyRealMethodInvoker.respond(GroovyRealMethodInvoker.java:34)
at org.spockframework.mock.runtime.MockInvocation.callRealMethod(MockInvocation.java:60)
at org.spockframework.mock.CallRealMethodResponse.respond(CallRealMethodResponse.java:29)
at org.spockframework.mock.runtime.MockController.handle(MockController.java:49)
at org.spockframework.mock.runtime.GroovyMockMetaClass.doInvokeMethod(GroovyMockMetaClass.java:104)
at org.spockframework.mock.runtime.GroovyMockMetaClass.invokeConstructor(GroovyMockMetaClass.java:50)
at org.spockframework.mock.runtime.MockInstantiator.instantiate(MockInstantiator.java:33)

Cheers,

Marcin

Lari Hotari

unread,
Oct 7, 2013, 1:39:20 AM10/7/13
to spockfr...@googlegroups.com

Here's a working example:
https://github.com/lhotari/filespy-spock-example/blob/master/src/test/groovy/FileSpySpec.groovy

running the example:
git clone https://github.com/lhotari/filespy-spock-example
cd filespy-spock-example
gradle test

requires these dependencies:
    testCompile 'cglib:cglib-nodep:2.2.2', 'org.objenesis:objenesis:1.3'

With Objenesis and Cglib on the class path, you add the GroovySpy like this:
        GroovySpy(File, global: true, useObjenesis: true)

For some reason I couldn't get these dependencies to work properly with @Grab.


This example doesn't work:

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
@Grab('org.objenesis:objenesis:1.3')
@Grab('cglib:cglib-nodep:2.2.2')


import spock.lang.Specification

class FileSpySpec extends Specification {
    def 'file spy example' () {
        given:
        def mockFile = Mock(File)
        GroovySpy(File, global: true, useObjenesis: true)
        when:
        def file = new File('testdir', 'testfile')
        file.delete()
        then :
        1 * new File('testdir','testfile') >> { mockFile }
        1 * mockFile.delete()
    }
}

results in

java.lang.IllegalAccessError: org/spockframework/compiler/InteractionRewriter$InteractionResponse
    at org.spockframework.compiler.InteractionRewriter.parseResults(InteractionRewriter.java:100)
    at org.spockframework.compiler.InteractionRewriter.isInteraction(InteractionRewriter.java:87)
    at org.spockframework.compiler.InteractionRewriter.rewrite(InteractionRewriter.java:70)
    at org.spockframework.compiler.DeepBlockRewriter.handleInteraction(DeepBlockRewriter.java:97)
    at org.spockframework.compiler.DeepBlockRewriter.doVisitExpressionStatement(DeepBlockRewriter.java:63)
    at org.spockframework.compiler.AbstractDeepBlockRewriter.visitExpressionStatement(AbstractDeepBlockRewriter.java:87)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)

The same code example works in the gradle build ( https://github.com/lhotari/filespy-spock-example)

Lari
--
You received this message because you are subscribed to the Google Groups "Spock Framework - User" group.
To unsubscribe from this group and stop receiving emails from it, send an email to spockframewor...@googlegroups.com.
To post to this group, send email to spockfr...@googlegroups.com.
Visit this group at http://groups.google.com/group/spockframework.
For more options, visit https://groups.google.com/groups/opt_out.

Peter Niederwieser

unread,
Oct 7, 2013, 11:21:56 AM10/7/13
to spockfr...@googlegroups.com
`useObjenesis = true` shouldn't be needed. If you want a constructor other than the default constructor to be used, you need to provide the constructor arguments. See http://docs.spockframework.org/en/latest/interaction_based_testing.html#spies for details.

Cheers,
Peter
signature.asc

Marcin Gryszko

unread,
Oct 8, 2013, 5:46:32 AM10/8/13
to spockfr...@googlegroups.com
Peter,

as far as I understood you, you provider constructor arguments to create a spy instance. However, I want to spy construction of an object that doesn't provide a default constructor (and I'm not able to add it).

My quick workaround was to use newInstance class method and use old Grails mocks to mock the call.



Marcin Gryszko      
Reply all
Reply to author
Forward
0 new messages