Disabling certain aspects during unit test runs

前端 未结 4 2075
我在风中等你
我在风中等你 2021-01-04 01:21

I have integration tests (load context) and unit tests running together. My code does aspectj compile time weaving using spring.

My problem is that my declared advi

相关标签:
4条回答
  • 2021-01-04 01:51

    The answer is simple: You want to use an if() pointcut expression.


    Update (after the question has also been updated): The originally provided link above should contain enough information, but for what it is worth, a short explanation and a simple example:

    An if() pointcut is a static aspect method returning a boolean. If the return value is true, it means that any combined pointcut like myPointcut() && if() matches as long as myPointcut() matches. For a return value of false the whole combined pointcut does not match, effectively deactivating any advice connected to the pointcut.

    So what can you do in a static if() pointcut?

    • evaluate a static boolean member of some tool class like TestMode.ACTIVE which is only true during unit or integration testing
    • evaluate an environment variable which is only set during testing
    • evaluate a Java system property which is only set during testing
    • and many more things

    If you want to do something fancier (and trickier) and performance is not so important, you can also try to dynamically determine whether the auto-wired aspect member variable equals null or not and only activate your pointcuts if the injected object is actually present. The only problem here is how to determine a member variable from a static method. I have no idea about Spring AOP, but in plain AspectJ there is the helper class Aspects with several overloaded methods named aspectOf(..). Assuming that your aspect is instantiated as a singleton, you could do something like this:

    @Pointcut("if()")
    public static boolean isActive() {
        return Aspects.aspectOf(PerformanceMonitorAspect.class).eventJournalService != null;
    }
    
    // ...
    
    @AfterReturning(pointcut = "isActive() && anyPublicMethod() && inService() && @annotation(eventJournal) && args(entity,..)", returning = "id")
    // ...
    
    @AfterThrowing(pointcut = "isActive() && anyPublicMethod() && inService() && @annotation(eventJournal) && args(entity,..)", throwing="ex")
    // ...
    
    0 讨论(0)
  • 2021-01-04 01:55

    You can write a method that returns if current execution was launched using JUnit framework.

    The method can check stack trace with Thread.currentThread().getStackTrace() and search for MockitoJUnitRunner presence.

    I tested this solution using a SpringJUnit4ClassRunner but I think could work with MockitoJUnitRunner.

    Also, you can have got a static boolean field like:

    private static boolean TEST_ENVIRONMENT = false;
    

    In a class present in your project (not in your tests) and check the value in the control method instead of use stack trace.

    When you run your tests, you can use @BeforeClass annotation to set TEST_ENVIRONMENT = true.

    This solution only gives you a way to know if your code is running from a test or not.

    0 讨论(0)
  • 2021-01-04 01:56

    Compile time weaving would inline the advice calls in the targeted methods identified by the pointcuts that you have. I personally feel that it is good to unit test with the compile time weaving in place, because at runtime your unit does include the class with the advice inlined?

    The thought I have to not include advice would be to have two different compile targets, one with compile time weaving, and one without, you should be able to do this through maven profiles, a dev profile not weaving advice in and a prod profile to weave the aspects in.

    0 讨论(0)
  • 2021-01-04 02:01

    I can only guess: The first thing is to have a separate Spring applicationContext-test.xml, without component-scan; In maven you can add a phase runtime excluding weaving jars for test.

    0 讨论(0)
提交回复
热议问题