Section 6.5. Testing a Service with Mocks

team bbl


6.5. Testing a Service with Mocks

Testing AOP applications seems difficult, but we'll give you a couple of techniques that simplify it. In this example, you'll learn how to use mock objects with aspects.

6.5.1. Why do I care?

When you use an aspect, it's often difficult to know if that aspect is working correctly. Since it's not main-line code, the testing strategy is not always clear. By mocking your aspect, you can confirm that it's fired when you expect it to be.

6.5.2. How do I do that?

We're going to create a test case, and call a target method within the test case (Examples Example 6-14 and Example 6-15).

Example 6-14. InterceptMe.java
// simple intercept to proxy public interface InterceptMe {     void interceptThisMethod( ); }

Example 6-15. MockInterceptorTest.java
public class MockInterceptorTest extends TestCase implements InterceptMe {     public void interceptThisMethod( ) {            // empty method     } }

Then, in our actual test method, we'll configure a proxy for the test case, and configure the proxy to intercept all the methods in our test interface (Example 6-16).

Example 6-16. ControllerTest.java
public void testLoggingInterceptor( ) throws Exception {         Advice advice = new LoggingAround( );         ProxyFactory proxyFactory = new ProxyFactory(this);         proxyFactory.addAdvice(advice);         InterceptMe target = (InterceptMe)proxyFactory.getProxy( );         target.interceptThisMethod( ); }

Finally, we'll use a mock object to record our expected behavior, and verify the behavior when we're done. In this case, remember the definition of the LoggingAround interceptor (Example 6-17).

Example 6-17. LoggingAround.java
public class LoggingAround implements MethodInterceptor {     private SessionFactory factory;     public SessionFactory getFactory( ) {         return factory;     }     public void setFactory(SessionFactory factory) {         this.factory = factory;     }     private void logEvent(String methodName, String message)             throws Exception {         Session s = null;         LogEvent le = new LogEvent(methodName, new Date( ), message);         try {             s = factory.openSession( );             s.save(le);         } catch (Exception ex) {             //log the exception         } finally {             s.close( );         }     }     public Object invoke(MethodInvocation methodInvocation)             throws Throwable {         logEvent(methodInvocation.getMethod( ).getName( ), "Entering call.");         Object result = methodInvocation.proceed( );         logEvent(methodInvocation.getMethod( ).getName( ), "Leaving call.");         return result;     } }

We're interested in verifying that it executes without actually having it write to the database. So we are going to provide a mock SessionFactory to mimic the behavior of Hibernate within the interceptor. Example 6-18 is the full test method with the mock objects added (note the programming injection of the mock SessionFactory into the interceptor).

Example 6-18. ControllerTest.java
public void testLoggingInterceptor( ) throws Exception {         MockControl factoryControl =             MockControl.createControl(SessionFactory.class);         MockControl sessionControl =             MockControl.createControl(Session.class);         SessionFactory mockFactory =             (SessionFactory)factoryControl.getMock( );         Session mockSession = (Session)sessionControl.getMock( );         // this sequence will execute once before the target method...          mockFactory.openSession( );         factoryControl.setReturnValue(mockSession);         mockSession.save(new LogEvent( ));         sessionControl.setMatcher(MockControl.ALWAYS_MATCHER);         sessionControl.setReturnValue(null);         mockSession.close( );         sessionControl.setReturnValue(null);         // and once after         mockFactory.openSession( );         factoryControl.setReturnValue(mockSession);         mockSession.save(new LogEvent( ));         sessionControl.setMatcher(MockControl.ALWAYS_MATCHER);         sessionControl.setReturnValue(null);         mockSession.close( );         sessionControl.setReturnValue(null);         factoryControl.replay( );         sessionControl.replay( );         Advice advice = new LoggingAround( );         ((LoggingAround)advice).setFactory(mockFactory);         ProxyFactory proxyFactory = new ProxyFactory(this);         proxyFactory.addAdvice(advice);         InterceptMe target = (InterceptMe)proxyFactory.getProxy( );         target.interceptThisMethod( );         factoryControl.verify( );         sessionControl.verify( );     }

6.5.3. What just happened?

When you think about it, our interceptors are just objects. We can mock APIs in them as easily as any other service. The trick is to take advantage of Spring's light weight, and run the container in the test case. We just advised our test case.

Here, we're just trying to make sure that the service works. We're not trying to test any of the façade methods, only the advice. We attached our new service to our test case method. When the test case called the method, the advice fired, and we verified that in the mock object.

    team bbl



    Spring. A developer's Notebook
    Spring: A Developers Notebook
    ISBN: 0596009100
    EAN: 2147483647
    Year: 2005
    Pages: 90

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net