1 Reply Latest reply on Sep 13, 2005 2:13 AM by skitching

    Replacing session beans with mock objects

    skitching

      For testing purposes I would like to be able to selectively replace certain stateless session beans with mock implementations.

      For Reference, these JIRA entries might be related but I'm not certain:
      * http://jira.jboss.com/jira/browse/EJBTHREE-204
      * http://jira.jboss.com/jira/browse/JBSEAM-61

      I have tried to do this by deploying both a real and a mock implementation of the same remote interface under two different JNDI names, and then at startup use JNDI calls to rebind some of the jndi names pointing at the real implementations to the objects representing the mock implementations.

      // a real stateless session bean
      @Remote public interface UserFacade {...}
      @Stateless public class UserFacadeBean implements UserFacade {..}

      // a mock implementation of that stateless session bean
      @Stateless(name="MyEmulatedUserFacadeBean")
      @RemoteBinding(jndiBinding="emulated/UserFacade")
      public class EmulatedUserFacadeBean implements UserFacade {...}

      A servlet filter then does this on init:
      InitialContext ic = new InitialContext();
      Enumeration propnames = props.propertyNames();
      while (propnames.hasMoreElements()) {
      String propName = (String) propnames.nextElement();
      if (propName.startsWith("jndi.")) {
      String targetJndiName = propName.substring(5);
      String srcJndiName = props.getProperty(propName);
      Object mockObject = ic.lookup(srcJndiName);
      ic.rebind(targetJndiName, mockObject);
      }
      }

      Setting up the devel.properties file with an entry like:
      jndi.com.acme.UserFacade=emulated/UserFacade
      should then cause any code within the app which looks up a UserFacade instance in jndi to get back a mock object instead.

      At least that was the plan. However this setup causes the following exception (see [1] below for full stacktrace)

      Caused by: java.lang.IllegalAccessException: Class org.jboss.aop.joinpoint.MethodInvocation can not access a member of class com.obsidium.omni.security.session.EmulatedLoginFacadeBean with modifiers "public"


      Perhaps jboss caches Method objects associated with the "real" implementation, and so when I swap in the "mock" implementation the cached Method object becomes invalid? Or is there some other cause?

      I also tried having the mock implementation *extend* the real implementation rather than have it implement the interface directly. But I then get this exception from my servlet filter code:

      javax.naming.NameNotFoundException: emulated not bound

      It would seem that jboss is ignoring the annotation
      @RemoteBinding(jndiBinding="emulated/UserFacade")
      when the class extends a class that is marked @Stateless.

      Alternatively, if someone could suggest a different way of temporarily replacing stateless session beans with mock implementations without actually overwriting the original code, recompiling and redeploying that would be great.


      ===============================
      [1]
      Caused by: java.lang.IllegalAccessException: Class org.jboss.aop.joinpoint.MethodInvocation can not access a member of class com.obsidium.omni.security.session.EmulatedLoginFacadeBean with modifiers "public"
      at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
      at java.lang.reflect.Method.invoke(Method.java:578)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:99)
      at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:32)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:66)
      at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:134)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:61)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:39)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:63)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:91)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:195)
      at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:107)
      at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:37)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88)
      at org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(StatelessRemoteProxy.java:88)