I'm trying to combine all these tools together. Here are the details and some screenshots of my project. I need post-compile time weave my source code.
Annotation:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Click {}
Aspect:
@Aspect
public class ClickAspect {
@Pointcut("@annotation(com.selenium.aspect.support.annotation.Click)")
public void clickAnn() {}
@Around("clickAnn()")
public void clickOnAction(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Clicking on a button");
joinPoint.proceed();
}
}
Page:
public class Page {
@FindBy(id = "menu-item-40489")
private WebElement search;
public Page(WebDriver driver) {
PageFactory.initElements(driver, this);
}
@Click
public void clickOnSearch() {
search.click();
}
}
Test class:
public class SeleniumAspectSupportTest {
private WebDriver driver;
private Page page;
@BeforeTest
public void initDriver() {
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS);
driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);
page = new Page(driver);
}
@AfterTest
public void dropDriver() {
driver.close();
}
@Test
public void simpleTest() {
driver.get("https://www.baeldung.com");
page.clickOnSearch();
System.out.println("DONE");
}
}
pom.xml:
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<configuration>
<complianceLevel>11</complianceLevel>
<source>11</source>
<target>11</target>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
aop.xml:
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<aspect name="com.selenium.aspect.support.controller.ClickAspect"/>
</aspects>
</aspectj>
The advise is not working, however the test passes. I've tried different aspectj library versions. What have I missed to make it work?
There are several things which could be improved in your POM, aspect and test code. But the root cause of your problem is that the aspect is first woven into the test class by AspectJ Maven Plugin, but then overwritten by Maven Compiler Plugin due to a rather cumbersome Maven Compiler default configuration, causing it to recompile everything. Therefore, you need to add this to your Maven Compiler configuration:
<!-- IMPORTANT -->
<useIncrementalCompilation>false</useIncrementalCompilation>
You can find an explanation in my answer here.
Other things you should improve:
aspectjweaver
dependency and aop.xml
, because you already use compile-time weaving and do not need a load-time weaving configuration on top of that. Either this or that, but not both.aspectjtools
a Maven Compiler dependency rather than a dependency for the Maven module itself. You only need the compiler inside the plugin, not during runtime. There, aspectjrt
is enough.execution()
joinpoints, because otherwise each aspect advice will be triggered twice, once for execution
and once for call
. You can see this on the console when running the test.<showWeaveInfo>true</showWeaveInfo>
for AspectJ Maven. Then you can also see the previous problem, i.e. doubly woven advice, more clearly during compile time.@Click
triggering the aspect.chromedriver.exe
background processes.<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SO_AJ_TestNGSelenium_69744638</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<aspectj.version>1.9.7</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<!-- IMPORTANT -->
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>11</complianceLevel>
<source>11</source>
<target>11</target>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
package com.selenium.aspect.support.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Click {}
package org.example;
import com.selenium.aspect.support.annotation.Click;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class Page {
@FindBy(className = "css-47sehv")
private WebElement cookiesAgree;
@FindBy(id = "menu-item-40489")
private WebElement search;
public Page(WebDriver driver) {
PageFactory.initElements(driver, this);
}
@Click
public void clickOnCookiesAgree() {
cookiesAgree.click();
}
@Click
public void clickOnSearch() {
search.click();
}
}
package org.example;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class ClickAspect {
@Pointcut("@annotation(com.selenium.aspect.support.annotation.Click) && execution(* *(..))")
public void clickAnn() {}
@Around("clickAnn()")
public void clickOnAction(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint + " -> Clicking on a button");
joinPoint.proceed();
}
}
package org.example;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;
public class SeleniumAspectSupportTest {
private WebDriver driver;
private Page page;
@BeforeTest
public void initDriver() {
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS);
driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);
page = new Page(driver);
}
@AfterTest
public void dropDriver() {
driver.close();
driver.quit();
}
@Test
public void simpleTest() {
driver.get("https://www.baeldung.com");
page.clickOnCookiesAgree();
page.clickOnSearch();
System.out.println("DONE");
}
}
The console log should read:
execution(void org.example.Page.clickOnCookiesAgree()) -> Clicking on a button
execution(void org.example.Page.clickOnSearch()) -> Clicking on a button