I'm stumped. I'm trying to test an AspectJ class. My Aspect class gets picked up perfectly when I'm running my application. However, I seem to be unable to get any Aspect class to intercept any method within a test.
I am using Spring 3.2.2, AspectJ 1.7.2 and Maven 4.
Here is the simple test I'm working with:
The Test AspectJ class
package my.package.path.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect
public class TestAOP {
private String message;
public TestAOP() {
}
@Pointcut("execution(* my.package.path.TestAOPClient.relayMessage(..))")
public void aopPointcut() {
}
@Around("aopPointcut()")
public String monitor(ProceedingJoinPoint pjp) throws Throwable {
String msg = (String)pjp.proceed();
this.setMessage(msg);
return msg;
}
}
The class whose method is being intercepted
package my.package.path.config;
public class TestAOPClient {
public String relayMessage(String msg) {
return msg;
}
}
The Test Class
package my.package.path.config;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@Configuration
@ContextConfiguration(classes={WebConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration("src/main/java")
public class AopConfigTest extends AbstractJUnit4SpringContextTests {
@Bean
public TestAOP testAop() throws Exception {
return new TestAOP();
}
@Test
public void assertTestConfigIsActive() {
TestAOPClient client = new TestAOPClient();
client.relayMessage("hello");
assertThat(((TestAOP)applicationContext.getBean("testAop")).getMessage(), equalTo("hello"));
}
}
The WebConfig file
package my.package.path.web.context;
@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass=false)
@ComponentScan(value={"my.package.path.config", "my.package.path.web"})
public class WebConfig {
}
Invariably, I will get the assertion error
Expected: "hello" but: was null
My WebApplicationContext seems to be picked up, since at runtime, I will get an ApplicationContext failed to load error if I specify a class that does not exist for my Aspect pointcut.
What am I missing?
AspectJ supports three kinds of advice. The kind of advice determines how it interacts with the join points it is defined over. Thus AspectJ divides advice into that which runs before its join points, that which runs after its join points, and that which runs in place of (or "around") its join points.
@AspectJ is a style to declare aspects in a java class using annotations. To enable @AspectJ, spring AOP provides @EnableAspectJAutoProxy annotation which will be annotated in java configuration. To work with spring AOP and @AspectJ support, we need to create a class annotated with @Aspect annotation.
Aspect: An aspect is a class that implements enterprise application concerns that cut across multiple classes, such as transaction management. Aspects can be a normal class configured through Spring XML configuration or we can use Spring AspectJ integration to define a class as Aspect using @Aspect annotation.
AspectJ implements both concerns and the weaving of crosscutting concerns using extensions of Java programming language.
It is kind of strange that you are using your unit test also as a @Configuration
source.
You should remove the @Configuration
annotation from the unit test and move the testAOP()
bean definition to WebConfig
. But most importantly the bean being advised must not be created manually, but by Spring:
@ContextConfiguration(classes={WebConfig.class})
@WebAppConfiguration("src/main/java")
public class AopConfigTest extends AbstractJUnit4SpringContextTests {
@Autowired
private TestAOP testAop;
@Autowired
private TestAOPClient client;
@Test
public void assertTestConfigIsActive() {
client.relayMessage("hello");
assertThat(((TestAOP)applicationContext.getBean("testAop")).getMessage(),
equalTo("hello"));
}
}
Updated config with the bean definition:
@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass=false)
@ComponentScan(value={"my.package.path.config", "my.package.path.web"})
public class WebConfig {
@Bean
public TestAOP testAop() throws Exception {
return new TestAOP();
}
@Bean
public TestAOPClient testAopClient() throws Exception {
return new TestAOPClient();
}
}
If your target was to test whether the AOP configuration works and TestAOP
is really a testing bean (not just a dummy name for this question), you can create a special TestConfig
configuration class, move the bean definition there and use it from the test @ContextConfiguration(classes={WebConfig.class,TestConfig.class})
.
Your pointcut configuration is wrong (package should be my.package.path.config to match your test client)
@Pointcut("execution(* my.package.path.TestAOPClient.relayMessage(..))")
and your client is
package my.package.path.config;
public class TestAOPClient {
...
change it to this
@Pointcut("execution(* my.package.path.config.TestAOPClient.relayMessage(..))")
should work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With