The Artima Developer Community
Sponsored Link

Java Buzz Forum
Testing advice/interceptors

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jon Tirsen

Posts: 33
Nickname: tirsen
Registered: Apr, 2003

Jon Tirsen is a developer at Lecando AB working a lot with open source and agile methodologies
Testing advice/interceptors Posted: Jun 26, 2003 10:51 AM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Jon Tirsen.
Original Post: Testing advice/interceptors
Feed Title: jutopia
Feed URL: http://sedoparking.com/search/registrar.php?domain=®istrar=sedopark
Feed Description: Ramblings on Java, AOP, TDD, agile and so on. some like it jutopic!
Latest Java Buzz Posts
Latest Java Buzz Posts by Jon Tirsen
Latest Posts From jutopia

Advertisement
This is the CacheInterceptorTest in Nanning. It outlines a simple recipe for testing interceptors:
public class CacheInterceptorTest extends AbstractAttributesTest {
    private Method someHeavyCalculationMethod;
    private CacheInterceptor cacheInterceptor;
    private boolean wasCalled;

    protected void setUp() throws Exception {
        super.setUp();

        cacheInterceptor = new CacheInterceptor();
        someHeavyCalculationMethod =
                CacheTestCalculations.class.getMethod("someHeavyCalculation",
                        new Class[] { double.class } );
    }

    public void testIntercept() {
        AspectInstance aspectInstance = new AspectInstance();
        MixinInstance mixin = new MixinInstance(CacheTestCalculations.class, null);
        mixin.addInterceptor(someHeavyCalculationMethod, cacheInterceptor);
        aspectInstance.addMixin(mixin);
        mixin.setTarget(new CacheTestCalculations() {
            public double someHeavyCalculation(double input) {
                wasCalled = true;
                return input;
            }
        });
        CacheTestCalculations cacheTestCalculations = (CacheTestCalculations) aspectInstance.getProxy();

        // non-cached call
        assertFalse(wasCalled);
        assertEquals(0, cacheTestCalculations.someHeavyCalculation(0), 0);
        assertTrue(wasCalled);

        // cached call
        wasCalled = false;
        assertEquals(0, cacheTestCalculations.someHeavyCalculation(0), 0);
        assertFalse(wasCalled);

        // flush cache and non-cached call
        cacheInterceptor.clearCache();
        wasCalled = false;
        assertEquals(0, cacheTestCalculations.someHeavyCalculation(0), 0);
        assertTrue(wasCalled);
    }

    // other tests removed...
}
There's a couple of points to make from this:
  1. Notice how I mock the target of the call with an anonymous class. The target informs the surrounding code wheather it was called through the boolean wasCalled. If the interceptor was to set up some specific state during the call the asserts would go inside the anonymous class, in that case the wasCalled is used just to ensure that target was invoked at all.
  2. There are lots of different ways of doing the above, depending on the situation. In this simple case I prefer the anonymous class due to it's simplicity (KISS). If there's more complex interactions you could use a simple String that you append each call to, a simple assert is used to check wheather calls where made in the correct order. You could also use dynamic mocks or some other variety, but don't get carried away with the fancy stuff, keep it simple. You might use an external class too, but that makes it a bit more awkward to use and a lot harder to read. You want to be able to grasp the entire test from looking at one place only. In most cases I prefer anonymous or inner classes over external classes for this reason. The CacheTestCalculations interface should have been inner but unfortunately the current version of QDox does not support inner-classes (so I can't use attributes on it).
  3. The advice is tested in isolation from any other parts of your system. This is what makes it a unit-test. This makes the test easy to understand and stable in the sense that it won't break for reasons that are outside itself. If the test breaks you know exactly where to look: in the advice you're testing.
  4. Test the advice extensively. Since the advice isn't tested together with other advice that it might interfere with it's important that the advice inner workings is defined in highest possible detail. A coverage tool is useful but doesn't quite do the trick here because a simple invocation will cover all of the tests, and that does not imply it's been properly tested (you need the asserts too, you know).
  5. In Nanning (just as in Aspect/J) several advice and introductions can be modularized into a single "aspect". It might make sense to write unit-tests for the aspect as a whole too. Any interference between several advice should be local to a single aspect only. Aspects should be orthogonal with respect to each other. This might not always be possible and in that case you might have to write tests that test the interference. Non-local interference should be minimized of course, as it makes the system a nightmare to maintain.

I'm not sure this testing strategy is usable for "non-fluid" AOP frameworks. That is AOP frameworks where aspects can't be dynamically deployed and undeployed. A well-known example of a non-fluid AOP framework is Aspect/J, to use this strategy in Aspect/J you would probably need to recompile between each unit-test. Not acceptable. Nanning is fluid of course. :-)

Read: Testing advice/interceptors

Topic: Checkstyle, a victim of its early success Previous Topic   Next Topic Topic: I used the

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use