2012-08-06 9 views
5

現在、私はaspectjを使っていくつかの監視ツールを開発中です。このツールは技術に依存しないように(可能な限り)、私はSpring for injectionを使用していません。しかし、私は自分の側面をユニットテストしたい。アスペクトを模擬する方法

アスペクト例:

@Aspect 
public class ClassLoadAspect { 
    private Repository repository; 

    public ClassLoadAspect() { 
     repository = OwlApiRepository.getInstance(); 
    } 

    @After("anyStaticInitialization()") 
    public void processStaticInitilization(JoinPoint jp) { 
     Class type = jp.getSourceLocation().getWithinType(); 
     if (type.isInterface()) { 
      repository.storeInterfaceInitialization(type); 
     } else if (type.isEnum()) { 
      repository.storeEnumInitialization(type); 
     } else { 
      repository.storeClassInitialization(type); 
     } 

    } 

    @Pointcut("staticinitialization(*) && !within(cz.cvut.kbss.odra..*)") 
    public void anyStaticInitialization() { 
    } 

    public Repository getRepository() { 
     return repository; 
    } 

    public void setRepository(Repository repository) { 
     this.repository = repository; 
    } 
} 

しかし、それゆえ、私は本当にユニットテスト(リポジトリフィールドは嘲笑されなければならない(使用mockito))を構築する方法を、知らない、しかし、私は制御の下で、アスペクトの作成を持っていません依存関係を手動で設定することはできません。インスタンスを取得するにはどうすればよいですか?あるいは、アスペクトのアスペクトをユニットテストする方法についての他のシナリオがあります。

ありがとうございました。

答えて

2

あなたはモックオブジェクトのハックを導入する独自の方法を見つけると言います。正確に何を嫌いにしていますか、どのように想像していますか?私は推測できます:

あなたは、メタ面でOwlApiRepository.getInstance()への呼び出しをグローバルに置き換えるという事実を嫌いますか?そして、あなたは、特に(私はPOJO注釈スタイルで不快に感じるので、私はネイティブのAspectJの構文を使用しています)側面のコンストラクタにモックオブジェクトの注入を制限することができます:

public privileged aspect ClassLoadTestAspect { 
    static boolean active = true; 

    declare precedence : ClassLoadTestAspect, ClassLoadAspect; 
    pointcut classLoadAspect() : 
     if(active) && 
     withincode(ClassLoadAspect.new()) && 
     call(* OwlApiRepository.getInstance()); 

    Object around() : classLoadAspect() { 
     return new MockRepository(); 
    } 
} 

をあなたも見ることができるように、メタ(アスペクトのこのバリアントをテスト)のアスペクトには、意志でオンとオフを切り替えるスイッチもあります。たぶん、これはまたあなたが嫌い​​だったものでした。私が言ったように、私は推測しています。あなたのフィードバックの後、私はより具体的に答えることができます。

編集:あなたの懸念については、私は可能な限りそれらに対処していると思う:

  • あなたはモックホルダーは必要ありません。

  • アスペクトは(非)活性化することができます。起動を他の条件に依存させるのは簡単なので、テスト環境でのみ有効です。これでもまだ十分でない場合は、制作の面でコンパイル時の織りを、テスト面ではロード時の織りを使用してください。この方法では、バイトコードは運用環境にも存在しません。

  • 私のバージョンでは何も置き換えられませんが、優れた外科医のように、侵襲性の低い方法で1箇所だけをカットします。

  • バイトコードの操作に関する懸念は、いくつかの理由で実際には理解できません。AspectJを使用する、つまり本質的にバイトコード操作(製織)。実行時にクラスを作成するMockitoを使用します。私はAspectJの欠点がどこにあるのかも理解していません。あなたは、「言語の標準的な手段」がどのように動作するか、またはテストのために提供すべきインターフェースをどのようにしたいか説明していません。あなたが持っていたとしても、あなたのために自分の言語(AJ)とツール(Mockito)を変更することはできません。

+0

私は私の溶液中で好きではないもの:静的メソッドのグローバルな交換が、それは難しいテストすることができます - (代わりに新しいものを設定するので)私は手動でレポジトリモックをリセットする必要があります。私はモックリポジトリオブジェクトにアクセスするためにモックホルダーを導入する必要もありました。 3番目のことは、私はモックを設定するためにバイトコードで気質が好きではないということです。私は本当にこれが言語の標準的な手段で行われなければならないと考えています(可能ならば、imhoはaspectj設計)。しかし、コードから、あなたの解決策は(少なくとも所有者は必要ありません):-)。 – malejpavouk

+0

ポイントは獲得、賞金はあなたのものです。ありがとう:-) – malejpavouk

+0

申し訳ありません。コメントに使用できる文字数が少なすぎるため、私は答えにコメントを追加することにしました。しかし、とにかく恩恵を受けてくれてありがとう。 :) – kriegaex

1

あなたのテストを分割することができます。最初にアスペクトのロジックをテストします。それはpojoだ。あなたはそれをテストすることができます。 2番目の部分はポイントカットをテストしています。この場合、同じポイントカットを持つ別の単純なアスペクトを作成します(たとえば、定数として抽出します)。多分そこにいくつかの専用のテストツールですが、私は、任意のを認識していないよ、それは私の心

1

私の現在のソリューションは、このAspectJのは、シングルトンファクトリメソッドをオーバーライドするためにハック導入されに来て最も簡単な方法だった

@Aspect 
public class MockingAspect { 

    @Around("call(synchronized static OwlApiRepository *(..))") 
    public OwlApiRepository processGetInstance(ProceedingJoinPoint jp) {  
     System.out.println("getting mock"); 
     return MockHolder.getMock(); 
    } 
} 
0

どのようにこれらの行に沿って、基本的にアスペクトを保持し続けるアスペクトの内側に別のインターフェイスに振る舞いを委譲し、アスペクト自体を模倣するのではなく、テストのためにそのインターフェイスをモックします。ここで擬似コードは次のとおりです。テストで今

public interface ClassLoadHelper{ 
    void processStaticInitialization(Class<?> clazz); 
} 

public class ClassLoadHelperImpl implements ClassLoadHelper{ 
    private Repository repository; 

    public ClassLoadHelperImpl() { 
     repository = OwlApiRepository.getInstance(); 
    } 

    void processStaticInitialization(Class<?> clazz){ 
     if (type.isInterface()) { 
      this.repository.storeInterfaceInitialization(type); 
     } else if (type.isEnum()) { 
      this.repository.storeEnumInitialization(type); 
     } else { 
      this.repository.storeClassInitialization(type); 
     }   
    } 
} 


@Aspect 
public class ClassLoadAspect { 
    private ClassLoadHelper classLoadHelper; 


    @After("anyStaticInitialization()") 
    public void processStaticInitilization(JoinPoint jp) { 
     Class<?> type = jp.getSourceLocation().getWithinType(); 
     this.classLoadHelper.processStaticInitialization(type); 

    } 

    @Pointcut("staticinitialization(*) && !within(cz.cvut.kbss.odra..*)") 
    public void anyStaticInitialization() { 
    } 

    public ClassLoadHelper getClassLoadHelper() { 
     return classLoadHelper; 
    } 

    public void setClassLoadHelper(ClassLoadHelper classLoadHelper) { 
     this.classLoadHelper = classLoadHelper; 
    } 
} 

あなたがこれを行うことができます:

ClassLoadAspect.aspectOf().setClassLoadHelper(mockClassLoadHelper); 
1

単体テストが適切でしょうか? これは、カスタムアプリケーション例外でスロー可能なオブジェクトをラップする目的で、カスタムアノテーションをテストするための小さな単体テストです。 (TestNGの+ Mockito)

public class ResourceApplicationExceptionAspectTest { 
@Mock 
private ProceedingJoinPoint pjp; 
@Mock 
private ResourceApplicationException resourceApplicationException; //annotation definition 

@BeforeMethod 
public void setUp() throws Exception { 
    MockitoAnnotations.initMocks(this); 

} 

@Test(groups ="unit", expectedExceptions = ResourceApplicationException.class) 
public void testWrapExceptionAdvice() throws Throwable { 

    ResourceApplicationExceptionAspect aspect = new ResourceApplicationExceptionAspect(); 

    when(pjp.proceed()).thenThrow(new NullPointerException()); 
    aspect.wrapExceptionAdvice(pjp, resourceApplicationException); 
}