I am working with:
The project is based in multi-modules.
In src/main/java
(main) I have some @Aspect
classes and they work how is expected. I can confirm it through Runtime and Testing
Now I need for JUnit through logging show the @Test
method name that is executed
Therefore in src/test/java
(test) I have the following:
class TestPointcut {
@Pointcut("execution(@org.junit.Test * *())")
public void testPointcut(){}
}
@Aspect
@Component
public class TestAspect {
private static final Logger logger = LoggerFactory.getLogger(TestAspect.class.getSimpleName());
@Before(value="TestPointcut.testPointcut()")
public void beforeAdviceTest(JoinPoint joinPoint){
logger.info("beforeAdviceTest - Test: {} - @Test: {}", joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName() );
}
}
Observe the second class has @Aspect
and @Component
therefore it is recognized by Spring
Note: I can confirm that If I write wrong the @Pointcut
syntax or expression I get errors.
The problem is when I execute my @Test
methods, For the TestAspect
class the @Before
advice never works.
I did a research in Google and I have seen that the @Pointcut("execution(@org.junit.Test * *())")
pattern is correct.
Even If I use a more explicit such as: @Pointcut(value="execution(public void com.manuel.jordan.controller.persona.*Test.*Test())")
, it does not work.
Consider I have the following for Gradle
project(':web-27-rest') {
description 'Web - Rest'
dependencies {
compile project(':web-27-service-api')
testRuntime project(':web-27-aop')
testRuntime project(':web-27-aop').sourceSets.test.output
What is missing or wrong?
Alpha:
One kind of Test classes are:
@Parameters
and @ClassRule
+ @Rule
Therefore:
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class})
@Transactional
public class PersonaServiceImplTest {
@ClassRule
public static final SpringClassRule SPRING_CLASS_RULE= new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Autowired
private PersonaService personaServiceImpl;
...
@Parameters
public static Collection<Persona[]> data() {
.....
});
}
...
@Test
@Sql(scripts={"classpath:....-script.sql"})
public void saveOneTest(){
....
}
Other are:
@WebAppConfiguration
) and either:
@Parameters
and @ClassRule
+ @Rule
@Parameters
and @ClassRule
+ @Rule
Therefore (below the second approach):
@Transactional
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})
public class PersonaDeleteOneControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private ResultActions resultActions;
...
@BeforeClass
public static void setUp_(){
...
}
@Before
public void setUp(){
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void deleteOneHtmlGetTest() throws Exception {
JUnit instantiates your test class. Thus, Spring is not involved and therefore cannot apply AOP advice to the test instance.
As was mentioned by Sergey Bespalov, the only way to have AspectJ advice applied to your test instance is to use compile-time or load-time weaving. Note that this would not be configured within Spring. Spring can be used to configure AOP for Spring-managed beans, but the test instance is managed by the testing framework (i.e., JUnit 4 in your scenario).
For tests using the Spring TestContext Framework, however, I would not recommend using AspectJ. Instead, the best solution is to implement a custom TestExecutionListener
that performs the logging. You could then register that TestExecutionListener
explicitly via @TestExecutionListeners
or have it picked up automatically for your entire suite. For the latter, see the discussion on automatic discovery in the Testing chapter of the Spring reference manual.
Regards,
Sam (author of the Spring TestContext Framework)
You can use AspectJ Compile or Load time weaving as alternative of spring-aop proxying. In such approach you will not depend on spring context complicated logic to apply advices in your code. Aspect code will be just inlined during compilation or class loading phase. Example below shows how to enable AspectJ Compile Time Weaving:
pom.xml
This Maven configuration enables AspectJ compiler that makes bytecode post processing of your classes.
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
</dependencies>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.6</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>${java.source}</source>
<target>${java.target}</target>
<complianceLevel>${java.target}</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>false</verbose>
<XnoInline>false</XnoInline>
</configuration>
<executions>
<execution>
<id>aspectj-compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>aspectj-compile-test</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
applicationContext.xml
Also you may need to add aspect instance to Spring Application Context for dependency injection.
<bean class="TestAspect" factory-method="aspectOf"/>
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