I have the following class that extends an Abstract class
public class MyConverter extends AbstractConverter<A, B> {
@Override
public B convert(A source) {
// implementation here
}
}
AbstractConverter
is from org.modelmapper
, it's declaration is the following:
public abstract class AbstractConverter<S, D> implements Converter<S, D> {
...
}
Now, from a Groovy file that uses Spock I want to mock my class:
class ATestOverThere extends Specification {
def myConverter = Mock(MyConverter) // THIS THROWS THE EXCEPTION
...
}
But I'm getting the folling exception when initializing the mock.
java.lang.IllegalArgumentException
at net.sf.cglib.proxy.BridgeMethodResolver.resolveAll(BridgeMethodResolver.java:61)
at net.sf.cglib.proxy.Enhancer.emitMethods(Enhancer.java:911)
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:498)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
at org.spockframework.mock.runtime.ProxyBasedMockFactory$CglibMockFactory.createMock(ProxyBasedMockFactory.java:154)
at org.spockframework.mock.runtime.ProxyBasedMockFactory.create(ProxyBasedMockFactory.java:68)
at org.spockframework.mock.runtime.JavaMockFactory.createInternal(JavaMockFactory.java:59)
at org.spockframework.mock.runtime.JavaMockFactory.create(JavaMockFactory.java:40)
at org.spockframework.mock.runtime.CompositeMockFactory.create(CompositeMockFactory.java:44)
at org.spockframework.lang.SpecInternals.createMock(SpecInternals.java:51)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:296)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:286)
at org.spockframework.lang.SpecInternals.MockImpl(SpecInternals.java:105)
at com.tuenti.services.argentina.business.products.sva.SvaManagerSpec.$spock_initializeFields(SvaManagerSpec.groovy:14)
Seems that I'm not able to mock a class that extends an abstract class with Spock, can I?
With Objenesis in addition to CGLIB on the classpath, as Michael Easter correctly said, your example works. No need to use ByteBuddy, though.
See also the Spock manual.
<!-- (...) -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
<!-- (...) -->
package de.scrum_master.stackoverflow;
import org.modelmapper.AbstractConverter;
public class MyConverter extends AbstractConverter<Integer, String> {
@Override
protected String convert(Integer source) {
return source.toString();
}
}
package de.scrum_master.stackoverflow
import spock.lang.Specification
class MyConverterTest extends Specification {
def "test"() {
given:
def myConverter = Mock(MyConverter) {
convert(_) >>> ["one", "two"] >> { callRealMethod() }
}
expect:
myConverter.convert(11) == "one"
myConverter.convert(22) == "two"
myConverter.convert(11) == "11"
myConverter.convert(22) == "22"
}
}