Java AspectJ 的 JUnit 测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41389015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:21:35  来源:igfitidea点击:

JUnit tests for AspectJ

javajunitmockitoaspectjspring-aop

提问by karthik

I am trying to write Junit tests for Custom Aspect. Here is the Aspect Class Snippet:

我正在尝试为自定义方面编写 Junit 测试。这是方面类片段:

@Aspect
@Component
public class SampleAspect {

    private static Logger log = LoggerFactory.getLogger(SampleAspect.class);

    @Around("execution(* org.springframework.data.mongodb.core.MongoOperations.*(..)) || execution(* org.springframework.web.client.RestOperations.*(..))")
    public Object intercept(final ProceedingJoinPoint point) throws Throwable {
        logger.info("invoked Cutom aspect");
         return point.proceed();

    }

}

So the above aspect intercepts whenever jointpoint matches the pointcut. Its working fine.

因此,只要关节点与切入点匹配,上述方面就会拦截。它的工作正常。

But my question is how to unit test that class. I have the following Junit Test:

但我的问题是如何对该类进行单元测试。我有以下 Junit 测试:

@Test(expected = MongoTimeoutException.class)
    public void TestWithMongoTemplate() {
        //MongoDocument class
        TestDocument test = new TestDocument();

        ApplicationContext ctx = new AnnotationConfigApplicationContext(TestMongoConfigurationMain.class);
        MongoTemplate mongoTemplate = ctx.getBean(MongoTemplate.class);

        //this call is being intercepted by SampleAspect
        mongoTemplate.save(test);

    }

So my mongoTemplate.save(test)in Junit is being intercepted by SampleAspectas it matches pointcut. But how should I make sure in junits(probably by asserting) that my SampleAspectis intercepting when that joint point is invoked?

所以我mongoTemplate.save(test)在 Junit 中被拦截,SampleAspect因为它匹配切入点。但是我应该如何确保在 junits 中(可能通过断言)SampleAspect在调用该联合点时我正在拦截?

I cannot assert on return value from intercept()as it does nothing special other than executing joint point. So my Junit cannot find any difference whether its being executed by aspect or a regular execution based on return values.

我不能断言 from 的返回值,intercept()因为它除了执行关节点之外没有什么特别的。所以我的 Junit 找不到任何区别,无论是按方面执行还是基于返回值的常规执行。

Any code snippets examples on aspect testing would be great if provided.Thanks

如果提供任何有关方面测试的代码片段示例,那就太好了。谢谢

采纳答案by kriegaex

I think what you are trying to test is aspect weaving and pointcut matching. Please note that that would be an integration rather than a unit test. If you really want to unit test your aspect logic and because you have tagged the question by "mockito" anyway, I suggest you do just that: Write a unit test and mock the aspect's joinpoint and maybe its other parameters, if any. Here is a slightly more complex example with some intra-aspect logic:

我认为您要测试的是方面编织和切入点匹配。请注意,这将是集成而不是单元测试。如果你真的想对你的方面逻辑进行单元测试,并且因为你已经用“mockito”标记了问题,我建议你这样做:编写一个单元测试并模拟方面的连接点,可能还有其他参数,如果有的话。这是一个稍微复杂一些的示例,其中包含一些方面内逻辑:

Java class to be targeted by aspect:

要按方面定位的 Java 类:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        new Application().doSomething(11);
        new Application().doSomething(-22);
        new Application().doSomething(333);
    }

    public void doSomething(int number) {
        System.out.println("Doing something with number " + number);
    }
}

Aspect under test:

被测方面:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class SampleAspect {
    @Around("execution(* doSomething(int)) && args(number)")
    public Object intercept(final ProceedingJoinPoint thisJoinPoint, int number) throws Throwable {
        System.out.println(thisJoinPoint + " -> " + number);
        if (number < 0)
            return thisJoinPoint.proceed(new Object[] { -number });
        if (number > 99)
            throw new RuntimeException("oops");
        return thisJoinPoint.proceed();
    }
}

Console log when running Application.main(..):

运行时的控制台日志Application.main(..)

As you can see, the aspect passes on 11, negates -22 and throws an exception for 333:

如您所见,方面传递 11,否定 -22 并为 333 抛出异常:

execution(void de.scrum_master.app.Application.doSomething(int)) -> 11
Doing something with number 11
execution(void de.scrum_master.app.Application.doSomething(int)) -> -22
Doing something with number 22
execution(void de.scrum_master.app.Application.doSomething(int)) -> 333
Exception in thread "main" java.lang.RuntimeException: oops
    at de.scrum_master.aspect.SampleAspect.intercept(SampleAspect.aj:15)
    at de.scrum_master.app.Application.doSomething(Application.java:10)
    at de.scrum_master.app.Application.main(Application.java:7)

Unit test for aspect:

方面的单元测试:

Now we really want to verify that the aspect does what it should and cover all execution paths:

现在我们真的想验证方面是否做了它应该做的事情并覆盖所有执行路径:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import static org.mockito.Mockito.*;

public class SampleAspectTest {
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock
    private ProceedingJoinPoint proceedingJoinPoint;

    private SampleAspect sampleAspect = new SampleAspect();

    @Test
    public void testPositiveSmallNumber() throws Throwable {
        sampleAspect.intercept(proceedingJoinPoint, 11);
        // 'proceed()' is called exactly once
        verify(proceedingJoinPoint, times(1)).proceed();
        // 'proceed(Object[])' is never called
        verify(proceedingJoinPoint, never()).proceed(null);
    }

    @Test
    public void testNegativeNumber() throws Throwable {
        sampleAspect.intercept(proceedingJoinPoint, -22);
        // 'proceed()' is never called
        verify(proceedingJoinPoint, never()).proceed();
        // 'proceed(Object[])' is called exactly once
        verify(proceedingJoinPoint, times(1)).proceed(new Object[] { 22 });
    }

    @Test(expected = RuntimeException.class)
    public void testPositiveLargeNumber() throws Throwable {
        sampleAspect.intercept(proceedingJoinPoint, 333);
    }
}

Now run this simple JUnit + Mockito test in order to test the aspect logic in isolation, notthe wiring/weaving logic. For the latter you would need another type of test.

现在运行这个简单的 JUnit + Mockito 测试,以便单独测试方面逻辑,而不是连接/编织逻辑。对于后者,您需要另一种类型的测试。

P.S.: Only for you I used JUnit and Mockito. Usually I just use Spock and its built-in mocking capabilities. ;-)

PS:我只为你使用了 JUnit 和 Mockito。通常我只使用 Spock 及其内置的模拟功能。;-)