Announcement Announcement Module
Collapse
No announcement yet.
Dynamically mock the business tier using Spring and Struts Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Dynamically mock the business tier using Spring and Struts

    I would like to unit test my struts actions. I'm using the DelegatingRequestProcessor with ContextLoaderPlugIn.

    I'd like to be able to test my actions while providing my own easymocked versions of my business tier interfaces.

    The problem is that with the DelegatingRequestProcessor, I'm not seeing an opportunity to inject my own easymocked interfaces as the dependencies that will be run. I'm using StrutsTestCase. I like this approach because it also excercises my struts-config file and manages framework details of struts such as actionerrors, actionmessages, and forward processing.

    I'm thinking I 'might' be able to create my own type of WebApplicationContext and somehow get Spring to using my created context which will sit at the ready to provide my easymocked interfaces rather than fully configured Spring beans.

    Can someone please discuss their strategies or recommend another approach?

    Thank you
    Joe

  • #2
    really bad idea was here....read next reply

    Comment


    • #3
      Problem:
      When using Spring's DelegatingRequestProcessor to inject Struts Action dependencies it is very difficult to provide dynamically mocked dependencies for those actions when using StrutsTestCase.

      I believe that doing such testing is very important as it allows you test Struts Actions isolated from the specifics of the business implementation while at the same time testing framework specifics such as struts-config, forwards, actionmessages, actionerrors, objects in session, etc..


      Solution:

      A dummy little class to hold some data, could be an inner class or something.....just work with me...

      Code:
      public class MethodData {
        String methodName;  //the method you're going to be calling
        Class argumentClassType; //Class type of dependency
        Object depenency;  //replace spring managed dependency with this
      
        ....getters/setters....
      }

      Extend DelegatingRequestProcessor to look for a list of dependencies to override....

      Code:
      public class DependencyReInjectableDelegatingRequestProcessor extends DelegatingRequestProcessor {
      
        private Collection overridenDependencies = new ArrayList();
      
        protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
      
          Action actionInjectedBySpring = super.getDelegateAction(mapping);
          Class actionClass = actionInjectedBySpring.getClass();
      
          for&#40;int i = 0; i < overridenDependencies.length; i++&#41;&#123;
            MethodData data = overridenDependencies&#91;i&#93;;
            String methodName = data.getMethodName&#40;&#41;;
            Class argType = data.getArgumentClassType&#40;&#41;;
            Object dependency = data.getDependency&#40;&#41;;
            try&#123;
              Method injectionMethod = actionClass.getMethod&#40;methodName, new Class&#91;&#93;&#123;argType&#125;&#41;;
              injectionMethod.invoke&#40;actionInjectedBySpring, new Object&#91;&#93;&#123;dependency&#125;&#41;;
            &#125;catch&#40;Exception ex&#41;&#123;
              System.err.println&#40;"I really should use a logger but it's an example..." + ex&#41;;
            &#125;
            
            
          &#125;
      
          return actionInjectedBySpring;  //But possibly re-injected in this method &#58;&#41;
      
        &#125;
      
        protected addDependencyToOverride&#40;String methodName, Class typeOfDependency, Object dependency&#41;&#123;
      
          MethodData data = new MethodData&#40;&#41;;
          data.setMethodName..
          data.setArgumentClassType..
          data.setDependency..
          overridenDependencies.add&#40;data&#41;;
      
        &#125;
      &#125;
      Now, have this RequestProcessor be the one you configure in struts-config.xml

      The great thing is that this processor simply delegates to Spring's implementation but if dependencies to overwrite have been implemented then they will be.

      In your struts test case base test class that you should make anyway just get a hold of this request processor through the apis and then cast it to the type of this custom request processor. Then you can call addDependencyToOverride for each type of dependency your actions can have. So call addDependencyToOVerride("setBusinessService", BusinessService.class, eacyMockedBusinessService) and now you have complete control over your business dependency in your struts actions so you have isolated your business layer.

      This results in every action being injected with all types of dependencies whether they want them or not. A simple refactoring can fix this but in my case I don't care.

      The key concept here is that you can with a little effort override Spring injected dependencies to provide your own dynamically mocked implementations.



      Is this lame, is this good, is there a better way?


      JOe

      Comment


      • #4
        UPDATE:

        I now have this working.

        The code I showed above isn't quite gonna cut it.

        I changed the RequestProcessor to look up the dependencies from an attribute in the servletContext. I created a SpringCactusStrutsTestCase class that has a method that puts the dependencies into the context. It's a sort of POBox pattern. It works great and doesn't require any hacking of struts or Spring or StrutsTestCase.

        If more detail is needed just let me know...


        JOe

        Comment


        • #5
          Can you elaborate on this? Facing the same issues..

          I'm working thru the same issue now, can you post some more code? The one that 'cuts it'?

          Comment

          Working...
          X