Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AspectJ advice not being executed through unit test

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?

like image 885
Emilie Avatar asked Jun 06 '13 20:06

Emilie


People also ask

What is advice in AspectJ?

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.

How do I enable AspectJ support?

@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.

What is the use of AspectJ in spring?

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.

What is AspectJ used for?

AspectJ implements both concerns and the weaving of crosscutting concerns using extensions of Java programming language.


2 Answers

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}).

like image 141
Pavel Horal Avatar answered Oct 24 '22 08:10

Pavel Horal


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.

like image 24
František Hartman Avatar answered Oct 24 '22 07:10

František Hartman