通过 aspectj 拦截拦截函数内的所有函数调用
Intercept all function calls inside a intercepted function by aspectj
我是 AspectJ 和思考的新手我想要实现的是下面的示例:
测试class :
public class Sample {
Home home = new Home();
Account account = new Account();
AccountAuthentication accountAuthentication = new AccountAuthentication();
@Test
public void loginInvalidCredentials(){
home.clickOnAccount();
account.login("Admin", "secret");
accountAuthentication.waitForPage();
Assert.assertTrue(true);
}
}
我想记录这样的输出:
packageName.Sample.loginInvalidCredentials
packageName.Home.clickOnAccount();
packageName.Account.login(userName = "Admin", Password ="secret");
packageName.AccountAuthentication.waitForPage();
packageName.Assert.assertTrue(value= true);
我已经使用 AspectJ
访问了函数 packageName.Sample.loginInvalidCredentials
的名称
@Aspect
public class AspectClass {
@Around("execution(* *(..)) && @annotation(org.testng.annotations.Test)")
public void around(ProceedingJoinPoint point) throws Throwable {
Method method = MethodSignature.class.cast(point.getSignature()).getMethod();
String methodName = method.getName();
System.out.println("Aspect called for method "+ point.getSignature().getDeclaringType().name +"."+methodName);
try {
//TODO intercept each function call inside the method without any custom anotation and get the value of parameters as well
joinPoint.proceed();
}
}
}
提前致谢。
我假设
- 你使用完整的 AspectJ 而不是像 Spring AOP 这样的东西(因为那样的话答案不适用),
- 你 不 想要递归地记录方法调用,但只是那些直接从你的
@Test
方法调用的方法。例如,如果 Account.login(..)
将在内部调用 Account.checkPassword(..)
,则不应记录。那也是可能的,但是解决方案看起来会有所不同。
- 您只想记录测试执行,而不做任何其他事情,因此不需要
@Around
建议,@Before
就足够了。
虚拟应用程序 类:
package de.scrum_master.app;
public class Account {
public void login(String user, String password) {
checkPassword(password);
}
public void checkPassword(String password) {}
}
package de.scrum_master.app;
public class AccountAuthentication {
public void waitForPage() {}
}
package de.scrum_master.app;
public class Home {
public void clickOnAccount() {
doSomethingElse();
}
public void doSomethingElse() {}
}
标记注释:
我自己创建了这个,因为我懒得用我通常不使用的 TestNG 设置项目。
package org.testng.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Test {}
示例应用程序:
package de.scrum_master.app;
import org.testng.annotations.Test;
public class Sample {
Home home = new Home();
Account account = new Account();
AccountAuthentication accountAuthentication = new AccountAuthentication();
@Test
public void loginInvalidCredentials() {
home.clickOnAccount();
account.login("Admin", "secret");
accountAuthentication.waitForPage();
}
public static void main(String[] args) {
new Sample().loginInvalidCredentials();
}
}
看点:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class TestExecutionLogger {
@Before("execution(* *(..)) && @annotation(org.testng.annotations.Test)")
public void logTest(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
@Before("call(* *(..)) && withincode(@org.testng.annotations.Test * *(..))")
public void logTestActions(JoinPoint joinPoint) {
System.out.println(" " + joinPoint);
}
}
控制台日志:
execution(void de.scrum_master.app.Sample.loginInvalidCredentials())
call(void de.scrum_master.app.Home.clickOnAccount())
call(void de.scrum_master.app.Account.login(String, String))
call(void de.scrum_master.app.AccountAuthentication.waitForPage())
当然,如果您真的认为需要从信息丰富的 AspectJ 日志输出中去除普通方法名称,您可以改进方面:
@Before("execution(* *(..)) && @annotation(org.testng.annotations.Test)")
public void logTest(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature());
}
@Before("call(* *(..)) && withincode(@org.testng.annotations.Test * *(..))")
public void logTestActions(JoinPoint joinPoint) {
System.out.println(" " + joinPoint.getSignature());
}
void de.scrum_master.app.Sample.loginInvalidCredentials()
void de.scrum_master.app.Home.clickOnAccount()
void de.scrum_master.app.Account.login(String, String)
void de.scrum_master.app.AccountAuthentication.waitForPage()
如果您有意删除方法的 return 类型或像您的示例中那样包含实际参数值,您可以进一步优化它,这很容易通过 JoinPoint.getArgs()
实现,但我保留了由你决定。你的问题是关于切入点,而不是关于如何从连接点中提取哪些信息。
我是 AspectJ 和思考的新手我想要实现的是下面的示例:
测试class :
public class Sample {
Home home = new Home();
Account account = new Account();
AccountAuthentication accountAuthentication = new AccountAuthentication();
@Test
public void loginInvalidCredentials(){
home.clickOnAccount();
account.login("Admin", "secret");
accountAuthentication.waitForPage();
Assert.assertTrue(true);
}
}
我想记录这样的输出:
packageName.Sample.loginInvalidCredentials
packageName.Home.clickOnAccount();
packageName.Account.login(userName = "Admin", Password ="secret");
packageName.AccountAuthentication.waitForPage();
packageName.Assert.assertTrue(value= true);
我已经使用 AspectJ
访问了函数packageName.Sample.loginInvalidCredentials
的名称
@Aspect
public class AspectClass {
@Around("execution(* *(..)) && @annotation(org.testng.annotations.Test)")
public void around(ProceedingJoinPoint point) throws Throwable {
Method method = MethodSignature.class.cast(point.getSignature()).getMethod();
String methodName = method.getName();
System.out.println("Aspect called for method "+ point.getSignature().getDeclaringType().name +"."+methodName);
try {
//TODO intercept each function call inside the method without any custom anotation and get the value of parameters as well
joinPoint.proceed();
}
}
}
提前致谢。
我假设
- 你使用完整的 AspectJ 而不是像 Spring AOP 这样的东西(因为那样的话答案不适用),
- 你 不 想要递归地记录方法调用,但只是那些直接从你的
@Test
方法调用的方法。例如,如果Account.login(..)
将在内部调用Account.checkPassword(..)
,则不应记录。那也是可能的,但是解决方案看起来会有所不同。 - 您只想记录测试执行,而不做任何其他事情,因此不需要
@Around
建议,@Before
就足够了。
虚拟应用程序 类:
package de.scrum_master.app;
public class Account {
public void login(String user, String password) {
checkPassword(password);
}
public void checkPassword(String password) {}
}
package de.scrum_master.app;
public class AccountAuthentication {
public void waitForPage() {}
}
package de.scrum_master.app;
public class Home {
public void clickOnAccount() {
doSomethingElse();
}
public void doSomethingElse() {}
}
标记注释:
我自己创建了这个,因为我懒得用我通常不使用的 TestNG 设置项目。
package org.testng.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Test {}
示例应用程序:
package de.scrum_master.app;
import org.testng.annotations.Test;
public class Sample {
Home home = new Home();
Account account = new Account();
AccountAuthentication accountAuthentication = new AccountAuthentication();
@Test
public void loginInvalidCredentials() {
home.clickOnAccount();
account.login("Admin", "secret");
accountAuthentication.waitForPage();
}
public static void main(String[] args) {
new Sample().loginInvalidCredentials();
}
}
看点:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class TestExecutionLogger {
@Before("execution(* *(..)) && @annotation(org.testng.annotations.Test)")
public void logTest(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
@Before("call(* *(..)) && withincode(@org.testng.annotations.Test * *(..))")
public void logTestActions(JoinPoint joinPoint) {
System.out.println(" " + joinPoint);
}
}
控制台日志:
execution(void de.scrum_master.app.Sample.loginInvalidCredentials())
call(void de.scrum_master.app.Home.clickOnAccount())
call(void de.scrum_master.app.Account.login(String, String))
call(void de.scrum_master.app.AccountAuthentication.waitForPage())
当然,如果您真的认为需要从信息丰富的 AspectJ 日志输出中去除普通方法名称,您可以改进方面:
@Before("execution(* *(..)) && @annotation(org.testng.annotations.Test)")
public void logTest(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature());
}
@Before("call(* *(..)) && withincode(@org.testng.annotations.Test * *(..))")
public void logTestActions(JoinPoint joinPoint) {
System.out.println(" " + joinPoint.getSignature());
}
void de.scrum_master.app.Sample.loginInvalidCredentials()
void de.scrum_master.app.Home.clickOnAccount()
void de.scrum_master.app.Account.login(String, String)
void de.scrum_master.app.AccountAuthentication.waitForPage()
如果您有意删除方法的 return 类型或像您的示例中那样包含实际参数值,您可以进一步优化它,这很容易通过 JoinPoint.getArgs()
实现,但我保留了由你决定。你的问题是关于切入点,而不是关于如何从连接点中提取哪些信息。