问题描述
我正在尝试为Custom Aspect编写Junit测试。这是Aspect Class Snippet:
I am trying to write Junit tests for Custom Aspect. Here is the Aspect Class Snippet:
@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.
但我的问题是如何对该类进行单元测试。我有以下Junit测试:
But my question is how to unit test that class. I have the following Junit Test:
@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);
}
所以我的 mongoTemplate.save( Junit中的
被 SampleAspect
拦截,因为它与切入点相匹配。但是,我应该如何确保junits(可能是断言)我的 SampleAspect
在调用该关节点时是否会拦截?
So my mongoTemplate.save(test)
in Junit is being intercepted by SampleAspect
as it matches pointcut. But how should I make sure in junits(probably by asserting) that my SampleAspect
is intercepting when that joint point is invoked?
我无法断言来自 intercept()
的返回值,因为除了执行关节点之外它没有什么特别之处。因此,我的Junit无论是基于返回值还是按方面执行还是常规执行都无法找到任何区别。
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.
如果提供的话,方面测试的任何代码片段示例都会很棒。谢谢
Any code snippets examples on aspect testing would be great if provided.Thanks
推荐答案
我认为你要测试的是方面编织和切入点匹配。请注意,这将是一个集成而不是单元测试。如果你真的想要对你的方面逻辑进行单元测试,并且因为你已经用mockito标记了问题,我建议你这样做:写一个单元测试并模拟方面的连接点,也许还有其他参数,如果有的话。以下是一个稍微复杂的示例,其中包含一些内部逻辑:
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:
要按方面定位的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);
}
}
测试中的方面:
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();
}
}
运行<$ c $时的控制台日志c> Application.main(..):
Console log when running Application.main(..)
:
如您所见,方面传递11,否定-22并抛出333的异常:
As you can see, the aspect passes on 11, negates -22 and throws an exception for 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)
方面的单元测试:
现在我们真的想验证方面是否应该做到了并覆盖所有执行路径:
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);
}
}
现在运行这个简单的JUnit + Mockito测试,以便单独测试方面逻辑,不布线/编织逻辑。对于后者,你需要另一种类型的测试。
Now run this simple JUnit + Mockito test in order to test the aspect logic in isolation, not the wiring/weaving logic. For the latter you would need another type of test.
P.S。:只为你我使用了JUnit和Mockito。通常我只使用Spock及其内置的模拟功能。 ; - )
P.S.: Only for you I used JUnit and Mockito. Usually I just use Spock and its built-in mocking capabilities. ;-)
这篇关于JUnit测试AspectJ的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!