Test annotation processor with spring test - java

I am using junit to test my annotation processor. The test is failing. It seems like never entering the joinpoint, without any exception.
My annotation is like this:
#Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface EventListener {
boolean isListening() default true;
boolean isDefaultListener() default true;
Class<SomeListener> subscriber() default None.class;
public static class None implements SomeListener {
... ...
}
}
And the processor like this:
#Aspect
public class ListenerProcessor {
#Pointcut("#annotation(com.xxx.common.event.annotation.EventListener)")
public void sign() {}
#Before("sign()")
public void anAdvice(JoinPoint joinPoint) { ***//this has never executed***
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
EventListener anno = method.getAnnotation(EventListener.class);
if (anno != null) {
if (anno.isListening()) {
if (anno.isDefaultListener())
doDefault();
else {
Class<SomeListener> clazz = anno.subscriber();
doCustomize(clazz);
}
} else {
... ...
}
}
}
... ...
}
My test is like this:
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = "classpath:applicationContext.xml")
public class EventListenerTest {
#Test
public final void test() {
//given
Long bef = countEvents();
//when
TestEntity1 t1 = appWithDefaultListener();
//then
TestEntity1 t2 = getEntityLike(t1);
Long aft = countEvents();
assertThat(t1).isEqualToComparingFieldByField(t2);
assertThat(aft).isEqualTo(bef+1);
}
#Transactional
#EventListener(isListening=true, isDefaultListener=true) ***//this seems does'nt work***
private TestEntity1 appWithDefaultListener() {
TestEntity1 t1 = new TestEntity1(...);
return myRepository.save(t1);
}
#Transactional(readOnly = true)
private TestEntity1 getEntityLike(TestEntity1 t1) {
TestEntity1 t2 = myRepository.findOne(Example.of(t1));
return t2;
}
}
My applicationContext.xml is like this:
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="eventProcessor"/>
</aop:aspectj-autoproxy>
<context:annotation-config />
<bean id="eventProcessor"
class="com.xxx.common.event.process.EventListenerProcessor"
scope="prototype"/>
And My pom has these dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.13.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>2.6.0</version>
</dependency>
What am I missing? Or any thing goes wrong?

Don't define appWithDefaultListener() and getEntityLike() as private methods in your test class.
Instead, you need to define them as non-private methods in another class that you configure as a bean in the test's ApplicationContext. Then have that bean #Autowired into your test class and invoke the methods via that reference so that your aspect is applied.

Related

PowerMock private void method with arguments

I'm looking for a unit test for Controllers using Mockito and PowerMock. Every controller has only private void methods with a single argument and a #Autowired service dependency:
public class ProjectController {
private ProjectServiceImpl service;
#Autowired
public void setInjectedBean(ProjectServiceImpl service) {
this.service = service;
}
private void createProject(String someString) {
// do stuff by calling service.doSomething(someString)
}
}
ProjectServiceImpl is annotated with #Service and has only a public void method with a String as argument. As it is too simple, I didn't bother providing the code.
My last attempt to accomplish that test looks like this:
#RunWith(PowerMockRunner.class)
#ExtendWith(MockitoExtension.class)
#PrepareForTest({ProjectController.class, ProjectServiceImpl.class})
class ProjectControllerTest {
#InjectMocks
private ProjectController controller;
#Mock
private ProjectServiceImplservice;
#Test
void createProject() throws Exception {
controller = PowerMockito.spy(new ProjectController());
PowerMockito.doNothing().when(controller, "createProject", new String(""));
}
}
Question 1: is it possible to make PowerMock work aside of Mockito?
Question 2: using PowerMock, what's the most appropriate way of calling for a private void method with argument?
IMPORTANT: Before marking this post as a duplicate, I personally challenge you finding any content how to do so. It seems like there is just no content showing not only how to make both work together, but make PowerMockito calls for a private void method with one or more arguments.
dependencies used for PowerMock:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

PowerMock is not intercepting new Instances

Hi I´m trying to test some legacy code that uses command patron. I couldn´t make work PowerMock propperly and I tryed to make a simple example to test if it could work.
I think that the problem is that the method whenNew() or expectNew() is not intercepting when in the original code a "new" instance is declared.
Here is the code:
ClassToTest
public class ClassToTest {
public ClassToTest() {
}
public ClassInstance getClassInstance() {
ClassInstance a = new ClassInstance(1);
return a;
}
}
ClassInstance
public class ClassInstance {
private int detector;
public ClassInstance(int detector) {
this.detector = detector;
}
public int getDetector() {
return detector;
}
public void setDetector(int detector) {
this.detector = detector;
}
}
The test
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassToTestTest.class, ClassInstance.class})
public class ClassToTestTest {
#Test
public void test() throws Exception {
ClassInstance n = new ClassInstance(2);
PowerMockito.whenNew(ClassInstance.class).withAnyArguments().thenReturn(n);
ClassToTest c = Mockito.spy(ClassToTest.class);
System.out.println(c.getClassInstance().getDetector());
}
}
And here is the pom.xml.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.18.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
So when I run the test, the expected value if PowerMockito intercepts the new instance should be 2 but the console gives me 1...

Autowired bean in spock test null after downgrading spring from 4.3.x to 3.2.x

I downgrade my application from spring 4.x to 3.x and now when I fire simple test in spock which using autowired bean, this bean is null.
#ContextConfiguration(classes = Configuration.class)
class SomeTestClass extends Specification {
#Autowired
SomeService someService
def "someService"(){
expect:
someService.returnHelloWorld() == "Hello World" // (<- NullPointer)
}
}
My pom.xml file:
<dependencies>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.12</version>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.1.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
After when I downgrade also spock-core/spring to 0.6-groovy-1.8 and groovy-all to 1.8 and fire my test it throws this exception:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'someAnotherBean' defined in file
../SomeBean.class: Instantiation of bean failed; nested exception
isorg.springframework.beans.BeanInstantiationException: Could
notinstantiate bean class [..SomeBean.class]: No default
constructorfound; nested exception is
java.lang.NoSuchMethodException:..SomeBean.()
This bean contains contructor which i used to intizialize final fieds in class:
#Component
#PropertySource("classpath:someproperties.properties")
public class HeaderFactory {
private final SomeObject someObject;
public HeaderFactory(#Value("${someProperty1}") String someProperty1, #Value("${someProperty2}") String someProperty2) {
SomeObject someObject = new SomeObject(someProperty1,someProperty2);
this.someObject = someObject;
}
}
Everything worked pretty well before I dowgraded spring version. Any ideas?
You could create a configuration class and define the problematic beans there:
#Configuration
class MyConfig {
#Value("${someProperty1}") String prop1;
#Value("${someProperty2}") String prop2
#Bean
public SomeBean someBean() {
SomeBean bean = new SomeBean(prop1, prop2);
return bean;
}
}
Documentation here: https://docs.spring.io/spring/docs/3.2.0.RELEASE/spring-framework-reference/html/new-in-3.0.html#new-feature-java-config
I resolved my issue by this way:
#Component
public class UrlBuilder {
private final String host;
private final String port;
private final String protocol;
#Autowired
public UrlBuilder(Environment env) {
this.protocol = env.getRequiredProperty("app.server.protocol").toLowercase();
this.serverHost = env.getRequiredProperty("app.server.host");
this.serverPort = env.getRequiredProperty("app.server.port", Integer.class);
}
}
Source

How to intercept method execution of inner non-spring class, which is defined in Spring managed bean?

I need to implement interceptor of inner class, outer class is managed by Spring
#Component
#Scope("prototype")
public class Outer {
protected class Inner {
protected void methodToIntercept() {
}
}
}
Outer.Inner.class may have childs (anonymous as well). Overriden methodToIntercept() should be intercepted as well
Documentation is pretty straightforward:
https://docs.spring.io/spring/docs/3.2.0.RELEASE/spring-framework-reference/htmlsingle/#aop-aj-ltw
According to documentation I configured everything in following way:
Project structure
-src
--main
---java
----temp
-----Config.java
-----MyAspect.java
-----Outer.java
-----SpringBean.java
--test
---resources
----META-INF
-----aop.xml
aop.xml
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<include within="temp.*"/>
</weaver>
<aspects>
<aspect name="temp.MyAspect"/>
</aspects>
</aspectj>
Config.java
#Configuration
#EnableLoadTimeWeaving
#ComponentScan("temp")
#Lazy
public class Config {
}
Outer.java
#Component
#Scope("prototype")
public class Outer {
#Component
public static class Inner {
public void methodToIntercept() {
}
}
}
MyAspect.java
#Aspect
#Component
public class MyAspect {
#Autowired
private SpringBean springBean;
#Around("execution(* temp.Outer.Inner.methodToIntercept())")
public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("success");
return joinPoint.proceed();
}
}
Dependencies
<dependencies>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aspectj/aspectjweaver -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-instrument -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
</dependencies>
It doesn't work as I expected unfortunately
Should it work with such configuration? What do I miss?
Thanks
Try to create your custom annotation and annotate the method.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface ServiceLoggable {
}
Your #Around will look like this
#Around("execution(* *(..)) && #annotation(com.company.core.log.ServiceLoggable)")
public Object logServiceMethods(ProceedingJoinPoint jp) throws Throwable {
...
}

Mockito mock constructor example

I'm trying to instantiate a mock object with Mockito. I found two examples in the article here, still this article is a very bad example for a newbie like me in Mockito.
Can somebody give me a better example of how it is done with either of the two options?
Simple when doing PowerMockito
public class A {
private final String name;
public A(String name) {
this.name= name;
}
public String sayHello() {
return "Hi " + this.name;
}}
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class MockA {
#Test
public void testSayHello throws Throwable {
A a = mock(A.class);
when(a.sayHello()).thenReturn("Hi PowerMockito");
PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
assertThat(new A("I am mockcked").sayHello(), equalTo("Yes, you are!"));
}
}
Dependencies
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>{mockito.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

Categories