当前位置: 首页 > 知识库问答 >
问题:

如何使用编译编织从项目的src目录中的测试目录强制AspectJ搜索?

夏侯衡
2023-03-14

实际上,这将是一个更复杂的问题。我只想在测试中使用AspectJ。找到了使用if()连接点和一些静态布尔字段的建议。此外,首先我开始使用aspect作为我的基本测试方法的内部静态类。经过一些实验,我把它换成了自己的班级,但实际上并没有得到我想要的结果。所以,我只是创建了一些测试项目。Maven pom。xml:

<?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>Testing</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <mockito.version>3.11.2</mockito.version>
        <aspectj.version>1.9.7</aspectj.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.7.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-inline</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
                <dependencies>
                    <!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-surefire-provider
-->
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                </dependencies>
                <!--<configuration>
                    <argLine>-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar</argLine>
                </configuration>-->
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.14.0</version>
                <configuration>
                    <complianceLevel>${maven.compiler.source}</complianceLevel>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <showWeaveInfo>true</showWeaveInfo>
                    <verbose>true</verbose>
                    <Xlint>ignore</Xlint>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <!-- use this goal to weave all your main classes -->
                            <goal>compile</goal>
                            <!-- use this goal to weave all your test classes -->
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

类别:A:

package classes;

public class A {
    private String a = "classes.A";

    public String getA()
    {
        return a;
    }

    public String getFromB()
    {
        return new B().getB();
    }
}

B:

package classes;

public class B {
    private String b = "classes.B";

    public String getB() {
        return b;
    }
}

测试类:

package aspectj;

import classes.A;
import classes.B;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;


public class NewTest {
    private static boolean useAspect = false;

    public static boolean isUseAspect() {
        return useAspect;
    }

    @BeforeEach
    void init()
    {
        useAspect = true;
    }

    @Test
    public void changeValue()
    {
        B b = new B();
        System.out.println(b.getB());
    }

    @Test
    public void changeValueInA()
    {
        A a = new A();
        System.out.println(a.getFromB());
    }
}

Aspect类

package aspectj;

import org.aspectj.lang.Aspects;
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 AspectB {

    @Pointcut("if()")
    public static boolean useAspect()
    {
        return NewTest.isUseAspect();
    }

    @Pointcut("call(* classes.B.getB())")
    public void callTestMethod() {}


    @Around("callTestMethod()")
    public String myAdvice(ProceedingJoinPoint point) throws Throwable {
        return "You have been hacked!";
    }
}

主要类别:

package classes;

public class TestOutputHere {
    public static void main(String[] args) {
        System.out.println(new A().getFromB());
    }
}

运行测试和主要方法后我得到了结果:

  • 更改值()-

第二个结果对我来说不合适...所以经过一些实验并删除AeyJ依赖项的测试范围,删除if()JointPoint(我们不能使用src中的测试类)并将Aspect类放在src中,我得到了结果:

  • 更改值()-

欲望的结果也不要脚给我。我真的不想为所有项目使用方面。在那之后,我只是试图为maven surefire插件使用一些带有配置的Load-Time编织:

<configuration>
 <argLine>
-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
</configuration>

我得到了我想要的结果:

  • 更改值()-

那么,成千上万封信后的问题在哪里?)问题是:

  1. 我可以通过编译编织而不使用AspectJ类加载器得到这个结果吗

我会非常感谢你的回答!

共有1个答案

宦高岑
2023-03-14

您的代码中有几个问题:

>

  • 您在每次测试之前设置useAspect=true,但在测试结束后永远不要重置为false。这会将上下文泄漏到您希望方面不活动的其他测试中。您应该清理它。

    方面有一个if()切入点,这取决于测试类中的静态方法。在正常情况下,测试类在应用程序运行时不可用。静态字段及其访问器方法(如果有)应该在方面类本身中。

    package aspectj;
    
    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 AspectB {
      private static boolean useAspect = false;
    
      public static void setUseAspect(boolean useAspect) {
        AspectB.useAspect = useAspect;
      }
    
      @Pointcut("call(* classes.B.getB()) && if()")
      public static boolean callTestMethod() {
        return useAspect;
      }
    
      @Around("callTestMethod()")
      public String myAdvice(ProceedingJoinPoint point) throws Throwable {
        return "You have been hacked!";
      }
    }
    
    package aspectj;
    
    import classes.A;
    import classes.B;
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    public class NewTest {
      @BeforeEach
      void init() {
        AspectB.setUseAspect(true);
      }
    
      @AfterEach
      void cleanUp() {
        AspectB.setUseAspect(false);
      }
    
      @Test
      public void changeValue() {
        B b = new B();
        System.out.println(b.getB());
      }
    
      @Test
      public void changeValueInA() {
        A a = new A();
        System.out.println(a.getFromB());
      }
    }
    

    很可能,你的方面是在src/test/java而不是src/main/java中定义的,这解释了为什么它只被编译成测试类而不是应用程序类。但后者是您所期望的,如果从一个应用程序类到另一个应用程序类的方法调用应该被拦截。因此,您需要将方面移动到主源代码中,并使aspectjrt具有编译范围,而不是测试范围。

    但是在这种情况下,如果方面只影响测试,我建议不要使用编译时编织(CTW),因为这意味着应用程序在其类路径上始终需要AspectJ运行时(见上文),即使方面处于非活动状态。只有当至少有时在应用程序运行时该方面也处于活动状态时,CTW才有意义。即使如此,如果负载时间编织(LTW)可能不是更好的解决方案,例如,如果它是一个很少使用的调试方面,这也是有争议的。CTW是生产方面的理想选择。在这种情况下,很明显,使用Java代理的LTW是正确的方法。正如您所说,您甚至不需要丑陋的静态字段和切入点。

  •  类似资料:
    • 我只想写一个JUnit测试用例,测试下面的代码是否成功地将目录复制到新目录。 请建议,我如何编写一个JUnit测试或模拟来测试上面的代码。

    • 问题内容: 有没有办法在单个Maven项目中编译多个Java源目录? 问题答案: 你可以使用build-helper添加新的源目录:

    • testng.xml TestNG将扫描所有类路径以寻找测试类(PackageUtils#findClassesInPackage)。 不需要的测试来自依赖项。 如何配置TestNG以只在maven项目测试目录中查找测试类(默认编译为)?

    • This is the name of the directory where compiled templates are located. By default this is "./templates_c", meaning that it will look for the compile directory in the same directory as the executing p

    • 问题内容: 我正在尝试使AspectJ编织工作在一个简单的Maven项目中,并且不确定它出了什么问题:当我使用“ mvn exec:java”运行代码时,看不到预期的输出。 我确定代码可以正常工作,因为我在STS中尝试了相同的方法,在这里工作良好。我只是想让AspectJ在Maven项目中工作。 任何有关如何调试此类问题的提示将不胜感激。 外观文件与代码位于同一文件夹中: Java文件: 问题答案