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"
}
}
Related
I was trying to follow multiple tutorials about the subject but I cannot understand how they support DI. To my basic understanding, DI should be supported by supplying extended/implemented classes object to the test, so the test will be able to be executed with multiple variations of the objects.
For example:
#Test
public void myTest(Base baseObj){
assertThis(baseObj);
assertThat(baseObj);
}
class Base {
//data
//methods
}
class Class1 extends Base{}
class Class2 extends Base{}
class Class3 extends Base{}
There should be a way to supply objects of the derived classes to the test. Am I wrong till here?
I couldn't understand from the explanations, how TestInfo class for example (or the other classes) helps me with that?
Can you enlighten me please?
You can do it like this:
public class Test1 {
#ParameterizedTest
#MethodSource("myTest_Arguments")
public void myTest(Base baseObj){
System.out.println(baseObj);
}
static Stream<Arguments> myTest_Arguments() {
return Stream.of(
Arguments.of(new Class1()),
Arguments.of(new Class2()),
Arguments.of(new Class3()));
}
}
The entire code is:
package com.example.demo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
class Base {}
class Class1 extends Base{}
class Class2 extends Base{}
class Class3 extends Base{}
public class Test1 {
#ParameterizedTest
#MethodSource("myTest_Arguments")
public void myTest(Base baseObj){
System.out.println(baseObj);
}
static Stream<Arguments> myTest_Arguments() {
return Stream.of(Arguments.of(new Class1()),Arguments.of(new Class2()),Arguments.of(new Class3()));
}
}
and the dependencies used are:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
Spring AOP is a proxy-based AOP framework. This means that to implement aspects to the target objects, it'll create proxies of that object. This is achieved using either of two ways:
JDK dynamic proxy – the preferred way for Spring AOP. Whenever the targeted object implements even one interface, then JDK dynamic proxy will be used
CGLIB proxy – if the target object doesn't implement an interface, then CGLIB proxy can be used
source
And yet, CGLIB is always used... This applies both to the standard Spring delivery (for example, using the #Transactional annotation) and using its written aspect
public interface MyService {
void methodFirst();
void methodSecond();
}
#Service
public class MyServiceImpl implements MyService {
#Override
#AnnotationCustom
public void methodFirst() {
System.out.println("methodFirst()");
methodSecond();
}
#Override
#AnnotationCustom
public void methodSecond() {
System.out.println("methodSecond()");
System.out.println();
}
#SpringBootApplication
public class AopTransactionalSpringApplication {
public static void main(String[] args) {
SpringApplication.run(AopTransactionalSpringApplication.class, args);
}
#Aspect
#Component
public class AspectCustom {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Pointcut("#annotation(aop.transactional.spring.aop.annotation.AnnotationCustom)")
public void annotatedMethodCustom() {}
#Before("annotatedMethodCustom() && publicMethod()")
public void printSomeMessage() {
System.out.println(" AspectCustom");
}
}
#SpringBootApplication
public class AopTransactionalSpringApplication {
public static void main(String[] args) {
SpringApplication.run(AopTransactionalSpringApplication.class, args);
}
test
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class AopTransactionalSpringApplicationTests {
}
class MyServiceTest extends AopTransactionalSpringApplicationTests {
#Autowired
private MyService myService;
#Test
void methodFirst() {
myService.methodFirst();
System.out.println();
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.source-target.version>11</java.source-target.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The documentation says that if we use the interface, then JDK will be used, and if the target class does not implement the interface, then inheritance will be used and then CGLIB will create a proxy, inheriting from the target class . But in debug mode, I actually observe something else .
Why is that?
Maybe I'm doing something wrong, please point out the mistakes in my understanding of this issue.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Class for which I m writing Junits:
public class AImpl implements AInterface {
public String method1(String id) throws Exception {
String s = Service.Factory.getInstance().generate(id);
return s;
}
}
Interface to be instantiated using its Inner class:
public interface Service {
String generate(String var1) throws Exception;
public static final class Factory {
private static Service instance = null;
public Factory() {
}
public static final Service getInstance() {
if (instance == null) {
instance = (Service)EnterpriseConfiguration.getInstance().loadImplementation(Service.class);
}
return instance;
}
}
}
I have tried powerMockito but it is not working.
#Test
public void generateTest() throws Exception {
Service.Factory innerClassMock = mock(Service.Factory.class);
String id= "id";
whenNew(Service.Factory.class).withArguments(anyString()).thenReturn(innerClassMock);
whenNew(innerClassMock.getInstance().generate("hjgh")).withAnyArguments().thenReturn(id);
id= AImpl.generate("hjgh");
Assert.assertEquals("id", id);
}
If I understand well your not cleary code you need this junit:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Service.Factory.class})
public class AImplTest {
private Service serviceMock;
#Before
public void setUp() {
PowerMockito.mockStatic(Service.Factory.class);
serviceMock = Mockito.mock(Service.class);
PowerMockito.when(Service.Factory.getInstance()).thenReturn(serviceMock);
}
#Test
public void generateTest() throws Exception {
Mockito.doReturn("mockid").when(serviceMock).generate(Mockito.anyString());
Assert.assertEquals("mockid", new AImpl().method1("aaa"));
}
}
Here my dependencies:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.28.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4 -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.4</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito2 -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.4</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock/powermock-core -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.4</version>
<scope>test</scope>
</dependency>
Having said that I would change your Service.Factory class: here you need a private constructor in order to implement correctly the singleton pattern.
I'm trying to spy my service class but I'm getting below exception, can you please help what I'm doing wrong here:
I tried to create Spy object using below code but is not working as expected
def myService = Spy(MyService)
MyInterface.groovy
interface MyInterface<T> {
public String welcome(T t);
}
MyService.groovy
#Service
class MyService implements MyInterface<WelcomeMessage> {
#Override
String welcome(WelcomeMessage welcomeMessage) {
try {
// Business logic
} catch (ex) {
// Catch Exception
}
}
}
import spock.lang.Specification
class myServiceTest extends Specification {
def "testWelcome"() {
setup: "create mock object"
def myService = Spy(MyService)
and: " and object with mock data"
when: "invoke welcomeMessage"
then: "Expecting no exception is thrown"
}
}
Exception:
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.SpyImpl(SpecInternals.java:169)
Thanks for your support
Could you provide your versions of spring, spock and cglib?
For these ones I could not reproduce the described issue:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.2-groovy-2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
<scope>test</scope>
</dependency>
The code I have is almost the same (instead WelcomeMessage I use String):
MyInterface.groovy
interface MyInterface<T> {
String welcome(T t);
}
MyService.groovy
import org.springframework.stereotype.Service
#Service
class MyService implements MyInterface<String> {
#Override
String welcome(String welcomeMessage) {
return welcomeMessage
}
}
MyServiceTest.groovy
import spock.lang.Specification
class MyServiceTest extends Specification {
def "Welcome"() {
setup: "create mock object"
def myService = Spy(MyService)
when: "invoke welcomeMessage"
def actual = myService.welcome("any")
then:
actual == "any"
}
}
I have a web application running in Wildfly which is using Spring and JPA. Now I am moving the login module of the application as a custom module in JBoss.
Code snippet is as below.
MyLoginModule
public class MyLoginModule extends AbstractServerLoginModule
{
private Principal caller;
private char[] credential;
private String[] roleList;
#Inject
#DaoQualifier
private Dao dao;
#Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
super.initialize(subject, callbackHandler, sharedState, options);
super.principalClassName = "com.myapp.login.LoginPrincipal";
}
#Override
public boolean login() throws LoginException
{
logger.info("inside login "+dao);
if (super.login())
{
................
}
else
{
............
}
}
}
DaoImpl class as given below.
public class DaoImpl implements Dao {
#Inject
private EntityManager em;
//implementation methods
}
Pom.xml dependencies
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.picketbox</groupId>
<artifactId>picketbox</artifactId>
<version>4.0.21.Beta1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.4.GA</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<scope>provided</scope>
</dependency>
beans.xml
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
When this jar is deployed in JBoss/modules and server started, the dao object is always coming as null. Is there something missing in my code?
as hwellmann said, login modules aren't managed beans. He is right about the manual lookup also. I'd like just to add a example code for the lookup:
public class CustomLoginModule extends AbstractServerLoginModule {
#Inject
AuthService authService;
#Override
public boolean login() throws LoginException {
if (authService == null) {
CdiHelper.programmaticInjection(CustomLoginModule.class, this);
}
authService.authenticate();
}...
The helper:
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class CdiHelper {
// Nicked from: http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single/#d0e5286
public static <T> void programmaticInjection(Class clazz, T injectionObject) throws NamingException {
InitialContext initialContext = new InitialContext();
Object lookup = initialContext.lookup("java:comp/BeanManager");
BeanManager beanManager = (BeanManager) lookup;
AnnotatedType annotatedType = beanManager.createAnnotatedType(clazz);
InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotatedType);
CreationalContext creationalContext = beanManager.createCreationalContext(null);
injectionTarget.inject(injectionObject, creationalContext);
creationalContext.release();
}
}
I've quoted this form https://developer.jboss.org/thread/196807 just in case the original post disappears.
Login modules aren't managed beans, so injection does not work. You have to look up your dependencies manually from JNDI or other suitable registries.
By the way, the built-in solution for dependency injection in Java EE 7 is CDI, so what's the point in using Spring?