JUnit测试AspectJ

我正在尝试为Custom Aspect编写Junit测试。 这是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(); } } 

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

但我的问题是如何对该类进行unit testing。 我有以下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); } 

因此,我在Junit中的mongoTemplate.save(test)SampleAspect拦截,因为它匹配切入点。 但是,我应该如何确保junits(可能是通过断言)我的SampleAspect在调用该关节点时会拦截?

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

如果提供方面测试的任何代码片段示例都会很棒。谢谢

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

方面要定位的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(); } } 

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

如你所见,方面传递11,否定-22并抛出333的exception:

 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 testing:

现在我们真的想validation方面是否应该完成它应该覆盖所有执行路径:

 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测试,以便隔离测试方面逻辑, 而不是布线/编织逻辑。 对于后者,您需要另一种类型的测试。

PS:只有你我才使用JUnit和Mockito。 通常我只使用Spock及其内置的模拟function。 ;-)