2016-12-30 242 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