0

I'm developing a Spring MVC web application (Java 6 and Spring 3.0.6 currently). I'm starting to write some Spring integration tests using Junit4 that extend AbstractTransactionalJUnit4SpringContextTests. I invoke these either through our Maven build or in the EclipseIDE (3.7). These tests invoke Controller methods (i.e., methods annotated with @RequestHandler in a class annotated with @Controller).

All was going well until I added aspect-based logging into the controller :

    // public controller methods
@Pointcut("execution(public * com.axiope.webapp.controller.*.*(..))")
private void publicControllerMethod() {
}
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
private void requestHandler(){}

@Pointcut("publicControllerMethod() && requestHandler() ")
private void controllerHandler(){}



// logs contoller exceptions
@AfterThrowing(
        pointcut="controllerHandler()",
        throwing="ex")
      public void logControllerExceptions(Throwable ex) {
    logger = LogFactory.getLog(ex.getClass());
    logger.error("Controller exception !" + ex.getMessage());   
    }

Now when I run tests through Maven I get an error like :

No unique bean of type [com.axiope.webapp.controller.StructuredDocumentController]
is defined: expected single bean but found 0: 

In the tests, I'm loading the controller from the applicationContext in the setUp method:

structuredDocumentController = applicationContext.getBean(
    StructuredDocumentController.class);

This error doesn't happen if I comment out the aspect. I suspect it has something to do with Spring proxying the controller and then the controller class isn't identifiable by its class name. I've tried declaring the controller as a bean in applicationContext.xml but this doesn't help. This problem also occurs when running the tests in Eclipse, so it's not a problem with my Maven configuration.

My question is : how can I get the controller bean detected in the tests?

Would be really grateful for any help - is it wrong to add aspects to methods in controller classes? Should I disable aspects somehow when testing? (Although ideally I'd like to see in the integration tests that logging is working properly).

Thanks very much

Richard

otter606
  • 335
  • 1
  • 4
  • 21

1 Answers1

0

Aspects are not the likely issue, you should be able to use them in the controller also without any problems.

My guess is that you are not loading up the correct context for your tests - how have you specified the application context to use for this test - is there @ContextConfiguration on your test class with the location, is the location to Root context(one specified through ContextLoaderListener) or Web application Context(one specified via DispatcherServlet).

Biju Kunjummen
  • 49,138
  • 14
  • 112
  • 125
  • Thanks - yes the context configuration points to all the required Spring configuration files. E.g., @ContextConfiguration( locations = {"classpath:/applicationContext-resources.xml", "classpath:/applicationContext-dao.xml", "classpath:/applicationContext-service.xml", "classpath:/applicationContext-test.xml", "/WEB-INF/applicationContext*.xml", "/WEB-INF/dispatcher-servlet.xml"}) – otter606 Aug 02 '12 at 20:27
  • Just to add that these files are specified in web.xml in the contextConfigLocation servlet context parameter – otter606 Aug 02 '12 at 20:33
  • Oh, 1 question, do you use AspectJ compile time/load time weaving or do you use Spring AOP with @AspectJ style annotations. you are right, proxying of the controllers is probably then what is causing the issue - do you derive your controllers from some interface/abstract class? – Biju Kunjummen Aug 02 '12 at 20:37
  • Spring AOP AspectJ annotations. The controllers are not implementing any interfaces ( the controller annotations are all on the implementation method). – otter606 Aug 03 '12 at 00:56
  • I am not able to reproduce the behavior that you are seeing - can you try one thing - instead of AbstractTransactionalJUnit4SpringContextTests, can you try with `@RunWith(SpringJunit4Runner.class)` and `@ContextConfiguration` with what you specified before and in your class `@Autowired StructuredDocumentController documentController` – Biju Kunjummen Aug 03 '12 at 01:29
  • Aha, it's now loading up the controller bean - but complaining about path mapping: `Cannot map handler 'strucDocCtrller' to URL path [/app/loadResource/value]: There is already handler of type [class $Proxy72] mapped.` This might be an issue with [not putting the handler annotations on an interface](http://stackoverflow.com/questions/5862991/spring-3-mvc-controller-with-aop-interceptors?rq=1). I'll try creating a Controller interface and put the path mapping annotations on the interface method declarations. Thanks very much for your help! – otter606 Aug 03 '12 at 09:07