Tests JUnit pour AspectJ


J'essaie d'écrire des tests Junit pour l'aspect personnalisé. Voici l'extrait de classe Aspect:

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

    }

}

Donc, l'aspect ci-dessus intercepte chaque fois que jointpoint correspond à pointcut. Son travail très bien.

Mais ma question est de savoir comment tester cette classe. J'ai le test Junit suivant:

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

    }

Donc mon mongoTemplate.save(test) dans Junit est intercepté par SampleAspect car il correspond à pointcut. Mais comment dois-je m'assurer en juin (probablement en affirmant) que mon SampleAspect intercepte quand ce point commun est invoqué?

Je ne peux pas affirmer sur la valeur de retour de intercept() car il ne fait rien de spécial autre que d'exécuter un point commun. Donc, mon Junit ne peut pas trouver de différence si elle est exécutée par aspect ou une exécution régulière basée sur des valeurs de retour.

Tous les exemples d'extraits de code sur les tests d'aspect seraient excellents s'ils étaient fournis.Merci

Author: Maciej Kowalski, 2016-12-30

1 answers

Je pense que ce que vous essayez de tester est le tissage d'aspect et la correspondance de pointcut. Veuillez noter que ce serait une intégration plutôt qu'un test unitaire. Si vous voulez vraiment tester votre logique d'aspect et parce que vous avez étiqueté la question par "mockito" de toute façon, je vous suggère de faire exactement cela: Écrire un test unitaire et se moquer du joinpoint de l'aspect et peut-être de ses autres paramètres, le cas échéant. Voici un exemple un peu plus complexe avec une logique intra-aspect:

Classe Java à cibler par aspect:

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

Aspect à l'essai:

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

Journal de la Console lors de l'exécution de Application.main(..):

Comme vous pouvez le voir, l'aspect passe sur 11, annule -22 et lève une exception pour 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)

Test unitaire pour l'aspect:

Maintenant, nous voulons vraiment vérifier que l'aspect fait ce qu'il devrait et couvre tous les chemins d'exécution:

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

Exécutez maintenant ce simple test JUnit + Mockito afin de tester la logique aspect isolément, pas la logique de câblage/tissage. Pour ce dernier, vous auriez besoin d'un autre type de test.

P.S.: Seulement pour vous j'ai utilisé JUnit et Mockito. Habituellement, j'utilise simplement Spock et ses capacités de moquerie intégrées. ;-)

 23
Author: kriegaex, 2016-12-31 10:13:44