5

私は現在、aspectjを使用していくつかの監視ツールに取り組んでいます。このツールは(可能な限り)テクノロジーに依存しないはずなので、私はインジェクションにSpringを使用していません。しかし、私は自分の側面を単体テストしたいと思っています。

アスペクトの例:

@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を使用))は本当にわかりませんが、アスペクトの作成を制御できないため、依存関係を手動で設定することはできません。インスタンスを取得するには何を呼び出す必要がありますか?または、aspectjアスペクトを単体テストする方法の他のシナリオがいくつかあります。

ありがとう。

4

5 に答える 5

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か所だけを切るように.

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

于 2012-08-10T17:18:19.663 に答える
1

テストを分割できます。最初にアスペクトのロジックをテストします。ポジョです。必要に応じてテストできます。2 番目の部分は、ポイントカットのテストです。この場合、同じポイントカットを持つ別の単純なアスペクトを作成します (たとえば、それらを定数として抽出します)。専用のテストツールがいくつかあるかもしれませんが、私は何も知りません。それが私の頭に浮かぶ最も簡単な方法でした

于 2012-08-06T09:12:36.303 に答える
1

単体テストをしたいだけですか?これは、throwable をカスタム アプリケーション例外にラップする目的で、アスペクトを使用してカスタム アノテーションをテストするための小さな単体テストです。(テスト + モッキート)

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);
}
于 2013-03-26T11:08:29.083 に答える
1

私の現在の解決策は、シングルトンのファクトリ メソッドをオーバーライドするために、この AspectJ ハックを導入することです

@Aspect
public class MockingAspect {

    @Around("call(synchronized static OwlApiRepository *(..))")
    public OwlApiRepository processGetInstance(ProceedingJoinPoint jp) {      
        System.out.println("getting mock");
        return MockHolder.getMock();
    }
}
于 2012-08-06T14:23:25.897 に答える
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);
于 2012-08-08T15:41:04.773 に答える