简体   繁体   English

如何动态检测 JUnit 测试?

[英]How to dynamically instrument JUnit tests?

I am using Invesdwin ( https://github.com/subes/invesdwin-instrument ) to dynamically load java agents into my Spring Boot project in the main method, before the context starts :在上下文开始之前,我正在使用 Invesdwin ( https://github.com/subes/invesdwin-instrument ) 在 main 方法中将 java 代理动态加载到我的 Spring Boot 项目中:

DynamicInstrumentationLoader.waitForInitialized();
DynamicInstrumentationLoader.initLoadTimeWeavingContext();

ApplicationContext springContext = SpringApplication.run(Some_Service.class);
...

This works great because it eliminates the need for adding -javaagent parameters when running the java -jar command from the command line.这很有效,因为它消除了从命令行运行 java -jar 命令时添加 -javaagent 参数的需要。

The issue arises when it comes to unit tests.当涉及到单元测试时就会出现这个问题。 Since they don't have a main method (that I can tap into that is), I cannot make those 2 lines run before the Spring Context initializes.由于它们没有 main 方法(我可以利用它),因此我无法在 Spring Context 初始化之前运行这 2 行。 Without those arguments, each test will cause the context to fail to load with this error :如果没有这些参数,每个测试都会导致上下文无法加载并显示以下错误:

ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-instrument-{version}.jar

I can work around this during the final build by setting up the Surefire plugin this way in my POM :我可以在最终构建期间通过在我的 POM 中以这种方式设置 Surefire 插件来解决这个问题:

<!--Maven Surefire Plugin-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>test</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <argLine>
                    -javaagent:lib/aspectjweaver-1.9.5.jar 
                    -javaagent:lib/spring-instrument-5.2.3.RELEASE.jar
                </argLine>
            </configuration>
          </plugin>

Unfortunately this only works during the final build phase.不幸的是,这只适用于最终构建阶段。 Running an individual test method in Eclipse will fail unless I manually add those arguments into the run configuration for that test which is a pain to say the least.在 Eclipse 中运行单个测试方法将失败,除非我手动将这些参数添加到该测试的运行配置中,这至少可以说是痛苦的。

I made a custom runner class in an attempt to make code run before the Spring context initializes, like so :我创建了一个自定义运行器类,试图在 Spring 上下文初始化之前运行代码,如下所示:

public class WeavingRunner extends SpringJUnit4ClassRunner
{
    public WeavingRunner(Class<?> clazz) throws InitializationError 
    {
        super(clazz);

        DynamicInstrumentationLoader.waitForInitialized();
        DynamicInstrumentationLoader.initLoadTimeWeavingContext();
    }
}

Although the Eclipse console does give me hints that the weaving is happening when my base test uses this runner class instead of SpringRunner, I get all sorts of weaving errors that seem to indicate the dynamic weaving hasn't happened soon enough :尽管 Eclipse 控制台确实给我提示,当我的基本测试使用这个运行器类而不是 SpringRunner 时,编织正在发生,但我收到了各种编织错误,似乎表明动态编织没有很快发生:

java.lang.NoSuchMethodException: com.something.SomeAspectClass.aspectOf()

Is there a known way to replicate code running in a main method when running JUnit tests?在运行 JUnit 测试时,是否有一种已知的方法来复制在 main 方法中运行的代码?

******EDIT****** ******编辑******

I noticed something extremely weird with this.我注意到了一些非常奇怪的事情。 If I run the package enclosing the tests as a JUnit test, it works!如果我将包含测试的包作为 JUnit 测试运行,它会起作用! The above weaving errors only appear when running the src/test/java folder as a JUnit test in Eclipse or running the app itself as a JUnit test (which I ultimately need).仅当在 Eclipse 中将 src/test/java 文件夹作为 JUnit 测试运行或将应用程序本身作为 JUnit 测试(我最终需要)运行时,才会出现上述编织错误。 The dynamic weaving is working but somehow something is making it only work when running individual tests or up to the enclosing package as a JUnit test.动态编织正在工作,但不知何故,它仅在运行单个测试或作为 JUnit 测试的封闭包时才起作用。 I hope that makes sense!我希望这是有道理的!

I was starting to suspect issues with my aop.xml file but how could that be the issue if running individual tests and even entire packages works fine?!我开始怀疑我的 aop.xml 文件有问题,但是如果运行单个测试甚至整个包都可以正常工作,那怎么会是问题?!

JUnit might do classpath scanning to discover unit tests. JUnit 可能会进行类路径扫描以发现单元测试。 Also junit classes with all their dependencies will be loaded before invesdwin-instrument can be invoked inside the test.此外,在可以在测试中调用 invesdwin-instrument 之前,将加载具有所有依赖项的 junit 类。 Thus the unit test class itself can not use aspects.因此单元测试类本身不能使用方面。 The only workaround I know for this is to put the aspect usage into a nested class which gets loaded after the test class is initialized and thus invesdwin-instrument is loaded.我知道的唯一解决方法是将方面用法放入嵌套类中,该类在测试类初始化后加载,从而加载 invesdwin-instrument。 An example for this pattern where @Transactional aspects are tested is here: https://github.com/invesdwin/invesdwin-context-persistence/blob/master/invesdwin-context-persistence-parent/invesdwin-context-persistence-jpa-hibernate/src/test/java/de/invesdwin/context/persistence/jpa/hibernate/MultiplePersistenceUnitsTest.java测试@Transactional 方面的此模式的示例如下: https : //github.com/invesdwin/invesdwin-context-persistence/blob/master/invesdwin-context-persistence-parent/invesdwin-context-persistence-jpa- hibernate/src/test/java/de/invesdwin/context/persistence/jpa/hibernate/MultiplePersistenceUnitsTest.java

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM