2016-12-30 243 views
4

我正在尝试为Custom Aspect编写Junit测试。这里是方面类代码片段:JUnit测试AspectJ

@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(); 

    } 

} 

因此,上面的方面截获每当联合点匹配切入点。它的工作正常。

但我的问题是如何单元测试该类。我有以下的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截获它匹配切入点。但是,我应该如何确保在联合点被调用时我的SampleAspect拦截(可能通过断言)?

我不能断言返回值从intercept(),因为除了执行联合点,它没有什么特别之处。所以我的Junit无论是通过方面执行还是基于返回值的常规执行都找不到任何区别。

任何代码片段上方面测试的例子是巨大的,如果provided.Thanks

回答

4

我知道你在想测试方面编织和切入点的匹配。请注意,这将是一个整合而不是单元测试。如果你真的想单元测试你的方面逻辑,并且因为你已经用“mockito”标记了问题,我建议你这样做:编写一个单元测试并模拟方面的连接点,或者其他参数(如果有的话)。这里有一个稍微更复杂的例子与一些帧内方面逻辑:

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); 
    } 
} 

看点下测试:

Java类被方面靶向

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个例外:

现在我们真的要验证方面:

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) 

的方面单元测试做什么它应该和涵盖所有的执行路径:

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,接线/编织逻辑。对于后者,你需要另一种类型的测试。

P.S .:只为你我使用JUnit和Mockito。通常我只是使用Spock和其内置的模拟功能。 ;-)

+0

这有助于单元测试。 @kriegaex。 – karthik

+1

对于任何想在本文中寻找Aspect集成测试的人,我所做的是我在跟踪任何连接点行为的方面创建了一个属性,然后在我的Junit中声明了该属性。这对我有效。 – karthik

+0

实际上,您不应将成员或手动簿记添加到某个方面,以便启用集成测试。它使生产过程变慢。有很多其他的方法来综合测试方面。也许这值得另一个问题。如果你创建一个,请随时不通知我,我会尽力回答。 – kriegaex