2012-08-06 16 views
5

Attualmente sto lavorando ad alcuni strumenti di monitoraggio usando aspectj. Poiché questo strumento dovrebbe essere indipendente dalla tecnologia (per quanto possibile), non sto utilizzando Spring for injection. Ma voglio che i miei aspetti siano testati unitamente.Come prendere in giro un aspetto

esempio Aspetto:

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

Comunque, io davvero non so, come costruire test di unità (il campo repository dovrebbe essere preso in giro (utilizzando Mockito)), ma non ho la creazione di aspetto sotto controllo, da qui Non riesco a impostare la dipendenza manualmente. Cosa dovrei chiamare per ottenere l'istanza? Oppure c'è qualche altro scenario su come testare l'aspetto di aspetti unitari.

Grazie.

risposta

2

Tu dici a trovare il proprio modo di introdurre l'oggetto fittizio hacky. Che cosa esattamente non ti piace e come immagini che sia? Posso solo indovinare:

Non ti piace il fatto che tu sostituisca globalmente le chiamate a OwlApiRepository.getInstance() nel tuo aspetto meta? Poi si potrebbe specificamente limitare l'iniezione oggetto fittizio al costruttore di aspetto (sto usando la sintassi nativa AspectJ perché mi sento a disagio con lo stile di annotazione POJO):

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

Come si può anche vedere, questa variante di una meta (aspetto -testing) ha anche un interruttore per accenderlo e spegnerlo a volontà. Forse era anche qualcosa che non ti piaceva. Come ho detto, immagino. Dopo il tuo feedback potrei essere in grado di rispondere in modo più specifico.

Edit: Per quanto riguarda le vostre preoccupazioni, penso che li ho affrontati, per quanto possibile:

  • non hai bisogno di un titolare di finto.

  • L'aspetto può essere (de) attivato. Sarebbe facile rendere la sua attivazione dipendente da altre condizioni, quindi è attiva solo nell'ambiente di test. Se questo non è ancora abbastanza, usa la tessitura in fase di compilazione per i tuoi aspetti di produzione e la tessitura in tempo di caricamento per il tuo aspetto di prova. In questo modo il suo codice byte non sarà nemmeno presente nell'ambiente di produzione.

  • La mia versione non sostituisce globalmente nulla, ma come un buon chirurgo taglia solo in un modo minimamente invasivo esattamente in un punto.

  • Non riesco a capire la tua preoccupazione sulla manipolazione del codice byte per diversi motivi: si utilizza AspectJ, cioè la manipolazione del codice byte intrinsecamente (tessitura). Usi Mockito che crea le classi in fase di runtime. Inoltre, non capisco dove si vede una carenza di AspectJ. Non hai spiegato come vuoi comportarti con i "mezzi standard del linguaggio" o quale interfaccia deve fornire per il test. Anche se lo avessi, non posso cambiare la lingua (AJ) e lo strumento (Mockito) di tua scelta per te.

+0

Quello che non mi piace nella mia soluzione: la sostituzione globale del metodo statico rende difficile per testare - devo resettare il mock repository manualmente (invece di impostare uno nuovo). Ho anche dovuto intrudire un portatore di mock per ottenere l'accesso all'oggetto repository finto. La terza cosa è che non mi piace temperare con il bytecode per impostare la simulazione, penso davvero che questo debba essere fatto con mezzi standard del linguaggio (se non è possibile, imho mostra una mancanza di aspetto design). Ma dal codice, la soluzione potrebbe fare (almeno non ha bisogno del titolare) :-). – malejpavouk

+0

Punto preso, la taglia è tua. Grazie :-) – malejpavouk

+0

Ci scusiamo per il rumore. Ho deciso di aggiungere i commenti alla mia risposta perché il numero di caratteri disponibili per i commenti era troppo piccolo. Ma grazie comunque per avermi assegnato la taglia. :) – kriegaex

1

puoi dividere i test. prima prova la logica dell'aspetto. è un pojo. puoi testarlo come vuoi la seconda parte sta testando i punti. in questo caso, crea un altro aspetto semplice con le stesse linee di punti (ad esempio, estraili come costante). forse ci sono alcuni strumenti di test dedicati ma io non sono a conoscenza di qualsiasi ed era il modo più semplice che mi vengono in mente

1

mia soluzione attuale è l'introduzione di questo AspectJ incidere al fine di eseguire l'override del metodo single fabbrica

@Aspect 
public class MockingAspect { 

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

Che ne dici di qualcosa in questo senso, in pratica continua a mantenere il tuo aspetto, nell'aspetto interno delegare il comportamento a un'altra interfaccia e prendere in giro l'interfaccia per i test, invece di prendere in giro l'aspetto stesso. Ecco un pseudocodice:

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

Ora nel tuo test che si può fare questo:

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

Vuoi solo test delle unità? Questo è un piccolo test di unità per testare un'annotazione personalizzata con aspetti allo scopo di avvolgere un throwable in un'eccezione dell'applicazione personalizzata. (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); 
} 
Problemi correlati