8 Replies Latest reply on Jan 28, 2010 12:18 PM by flavia.rainone

    withincode from JUnit test not working

    nizzy

      Hi Guys,

       

      I have been working on this issue off and on for a while now. Here are my findings, hopefully someone will be able to help me!

       

      Environment

      ------------------

      Standalone Hibernate 3.2.4.GA

      Standalone JBoss AOP 2.0.1.GA

      Junit 4.4

      Log4j

      Running via Eclipse 3.3.2

       

      I can successfully do everything I need to use AOP for the purposes of JUnit testing, except using the withincode expression. It will work when I try it from a POJO (non-JUnit class), however nothing I have done so far can get it to intercept a call from within a JUnit test.

       

      I have been using loadtime weaving which made any debugging extremely difficult and so I have updated my project to use compile time weaving, I found this easier to work with.

       

      Initially I suspected the issue may be classpath related, i.e. thought if JUnit archives not on loatime classpath then would the instrumentation of the JUnit class fail, still not sure if this is accurate.

       

      However all I have been able to do this far is repeat the results for both Compile/Load Time Weaving. That is I can intercept call to constructor of class and replace with mock class, etc, however I cannot get withincode to expression to work in conjunction with call expression.

       

      jboss-aop.xml

       

      <?xml version="1.0" encoding="UTF-8"?>
      <aop>
           <bind pointcut="execution(public $typedef{persistenceHelperTypeDef}->new(java.lang.String))">
             <interceptor class="com.ecebs.unittest.aop.interceptor.GenericInterceptor">
                 <attribute name="mockObjectName">MockPersistenceHelper</attribute>
             </interceptor>
          </bind>
      
          <typedef name="persistenceHelperTypeDef" 
                  expr="class($instanceof{com.ecebs.unittest.aop.IPersistenceHelper}) 
                            AND !class(com.ecebs.unittest.aop.mock.*)" />
                     
          <aspect class="com.ecebs.unittest.aop.aspect.ExceptionInjector" scope="PER_CLASS" />
          
          <bind pointcut="call(public void com.ecebs.unittest.aop.ExampleManagerBean->createObject(..))
                                   AND withincode(public void com.ecebs.unittest.aop.ExampleManagerBeanTest->testCreateObject_MultefileException())">
                                   
               <advice name="throwMultefileException" aspect="com.ecebs.unittest.aop.aspect.ExceptionInjector" />
          </bind>
                             
      </aop>
      

       

      Output, including verbose aopc info

      Buildfile: C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\build.xml
      aopclean:
           [echo] cleaning build, aopclasses directory
         [delete] Deleting directory C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\build
         [delete] Deleting directory C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses
      compile:
           [echo] compiling source
          [mkdir] Created dir: C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\build
          [javac] Compiling 17 source files to C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\build
      aop:
          [mkdir] Created dir: C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses
           [copy] Copying 18 files to C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses
           [copy] Copying 2 files to C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses
           [echo] Running AOPC target to instrument classes
           [aopc] [info] Total length of filenames to be compiled is greater than 1000, listing files in --SOURCEPATH: C:\DOCUME~1\ALANN~2.ECE\LOCALS~1\Temp\src6131407091635596476.tmp
           [aopc] log4j:WARN No appenders could be found for logger (org.jboss.aop.instrument.InstrumentorFactory).
           [aopc] log4j:WARN Please initialize the log4j system properly.
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\MultefileException.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\AbstractJPAHelper.class
           [aopc] [compiled] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelperTest.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\IPersistenceHelper.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\aspect\ExceptionInjector.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\mock\MockService.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\Application.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\Environment.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\AbstractJPAHelper.class
           [aopc] [compiled] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelper.class
           [aopc] [compiled] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelperTest$1.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\ExampleManager.class
           [aopc] [compiled] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\ExampleManagerBean.class
           [aopc] [compiled] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\ExampleManagerBeanTest.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\MultefileRuntimeException.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\interceptor\GenericInterceptor.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\EnvironmentPK.class
           [aopc] [compiled] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\mock\MockPersistenceHelper.class
           [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\Revision.class
           [aopc] Build Successful: 484 ms
      do-test-junit:
          [junit] Running com.ecebs.unittest.aop.ExampleManagerBeanTest
          [junit] Tests run: 3, Failures: 2, Errors: 0, Time elapsed: 0.547 sec
          [junit] Test com.ecebs.unittest.aop.ExampleManagerBeanTest FAILED
      [junitreport] Processing C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\reports\junit\TESTS-TestSuites.xml to C:\DOCUME~1\ALANN~2.ECE\LOCALS~1\Temp\null1590394285
      [junitreport] Loading stylesheet jar:file:/C:/Program%20Files/eclipse/eclipse-j2ee/plugins/org.apache.ant_1.7.0.v200706080842/lib/ant-junit.jar!/org/apache/tools/ant/taskdefs/optional/junit/xsl/junit-frames.xsl
      [junitreport] Transform time: 250ms
      [junitreport] Deleting: C:\DOCUME~1\ALANN~2.ECE\LOCALS~1\Temp\null1590394285
      BUILD SUCCESSFUL
      Total time: 2 seconds

      As can be seen from the jboss-aop.xml I'm trying to intercept the call to the ExampleManagerBean->createObject(..) method when called from within the ExamplemanagerBeanTest. I assume that when the aopc output states that a class has been compiled it mean that aop has recognized that instrumentation was required. So from the output I can see that;

       

      PersistenceHelperTest.class

      PersistenceHelper.class

      PersistenceHelperTest$1.class

      ExampleManagerBean.class

      ExampleManagerBeanTest.class

      MockPersistenceHelper.class

      Have been instrumented, is this assumption correct?

       

      I use the following ant targets

       

           <target name="aop" depends="compile">
                <property name="classes.dir" value="aopclasses" />
                
                <mkdir dir="${classes.dir}" />
                
              <!-- copy the classes to a aopclasses directory-->
              <copy todir="${classes.dir}">
                    <fileset dir="build" includes="**/*.class"/>    
              </copy>
                
                <!-- copy the jboss-aop.xml to aopclasses directory so can be located at runtime -->
              <copy todir="${classes.dir}">
                    <fileset dir="test" includes="META-INF/*.*"/>    
              </copy>
              
              <!-- setup the ant task and the required classpaths -->
              <taskdef name="aopc" 
                    classname="org.jboss.aop.ant.AopC" 
                    classpathref="project.class.path"/>
                    
              <path id="jboss.aop.classpath">
                  <pathelement path="${jboss-aop-2.0.1.GA.dir}/jboss-aop-single.jar"/>
              </path>
                
              <path id="aop.classpath">
                   <pathelement path="${classes.dir}"/>
                   <fileset dir="${log4j.dir}" includes="*.jar"/>
                   <fileset dir="${JUnit4.dir}" includes="*.jar"/>
              </path>
                    
                <echo message="Running AOPC target to instrument classes" />
                
              <!-- instrument the classes with the first call to aopc -->
              <aopc compilerclasspathref="jboss.aop.classpath" report="false" verbose="true">
                  
                   <!-- define aop classpath - cp for dependant classes in src -->
                   <classpath refid="aop.classpath"/> 
                   
                   <!-- define location of classes to be instrumented -->
                  <src path="${classes.dir}"/>
                  <include name="**/*.class"/>
                   <aoppath path="test/META-INF/jboss-aop.xml"/>
                   
              </aopc>  
           </target>
           
           <path id="test.class.path">
                <fileset dir="${jboss-aop-2.0.1.GA.dir}" includes="jboss-aop-single.jar" />
                <fileset dir="${log4j.dir}" includes="*.jar" />
                <fileset dir="${JUnit4.dir}" includes="*.jar"/>
                <fileset dir="${hibernate.dir}" includes="*.jar"/>
           </path>
           
           <target name="do-test-junit" depends="aopclean, aop">
                <mkdir dir="reports/junit/.xml" />
                <junit fork="no" printsummary="yes" haltonfailure="no" errorproperty="test.junit.failed">
                     <classpath>
                          <path path="${classes.dir}" />
                          <path refid="test.class.path" />
                     </classpath>
                     <formatter type="xml" />
                     <batchtest todir="reports/junit/.xml">
                          <fileset dir="${classes.dir}">
                               <include name="**/ExampleManagerBeanTest.class" />
                          </fileset>
                     </batchtest>
                </junit>
                
                <junitreport todir="reports/junit">
                     <fileset dir="reports/junit/.xml">
                          <include name="*.xml" />
                     </fileset>
                     <report format="frames" todir="reports/junit" />
                </junitreport>
           </target>     
           
           <target name="aopclean">
                <echo message="cleaning build, aopclasses directory"/>
                <delete dir="build"/>
                <delete dir="aopclasses"/>
           </target>
      

       

      Please can someone have a look at this issue. Let me know anything I can do that will assist any investigation, i.e. inclusion of code, etc.

       

      It is our intention to use AOP as a tool to improve our unit-testing and so I would really like to be able to solve this issue. I'm at the point I don't have too much more time to spend on it.

        • 1. Re: withincode from JUnit test not working
          nizzy

          No one with any ideas?

          Will I just raise this as a bug?

          • 2. Re: withincode from JUnit test not working
            flavia.rainone

            nizzy wrote:


            As can be seen from the jboss-aop.xml I'm trying to intercept the call to the ExampleManagerBean->createObject(..) method when called from within the ExamplemanagerBeanTest. I assume that when the aopc output states that a class has been compiled it mean that aop has recognized that instrumentation was required. So from the output I can see that;

             

            PersistenceHelperTest.class

            PersistenceHelper.class

            PersistenceHelperTest$1.class

            ExampleManagerBean.class

            ExampleManagerBeanTest.class

            MockPersistenceHelper.class

            Have been instrumented, is this assumption correct?

             

            Yes, your assumption is correct.

             

            We need to find out why the call joinpoint is not being intercepted. First thing I would try is replacing the withincode by a simple within and then, if the call you want to intercept is not being intercepted this way, I would try using the pointcut with the call expression alone, that is, without the withincode part. For testing purposes, this can be useful to identify if the problem is the withincode, or if it is intercepting the call from inside the test class.

             

            The JBoss AOP tests are reproducing both scenarios, and all of our tests are passing, se we also need to find out what is different in your scenario. This will be the next step.

            • 3. Re: withincode from JUnit test not working
              nizzy

              Thanks for the response!

               

              "First thing I would try is replacing the withincode by a simple within"

               

              <aspect class="com.ecebs.unittest.aop.aspect.ExceptionInjector" scope="PER_CLASS" />
              
              <bind pointcut="call(public void com.ecebs.unittest.aop.ExampleManagerBean->createObject(..))
                                           AND within(com.ecebs.unittest.aop.ExampleManagerBeanTest)">
                                           
                <advice name="throwMultefileException" aspect="com.ecebs.unittest.aop.aspect.ExceptionInjector" />
              </bind>
              
              • 4. Re: withincode from JUnit test not working
                nizzy

                Sorry didnt mean to post that, wasnt finished

                 

                What I was going to say was that none of the classes were compiled with the jboss-aop.xml from previous post.

                 

                "I would try using the pointcut with the call expression alone"

                <aspect class="com.ecebs.unittest.aop.aspect.ExceptionInjector" scope="PER_CLASS" />
                
                <bind pointcut="call(public void com.ecebs.unittest.aop.ExampleManagerBean->createObject(..))">
                                             
                   <advice name="throwMultefileException" aspect="com.ecebs.unittest.aop.aspect.ExceptionInjector" />
                </bind>
                

                 

                Again none of the classes were compiled.

                 

                [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\MultefileException.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\AbstractJPAHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelperTest.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\IPersistenceHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\aspect\ExceptionInjector.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\mock\MockService.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\Application.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\Environment.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\AbstractJPAHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelperTest$1.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\ExampleManager.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\ExampleManagerBean.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\ExampleManagerBeanTest.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\MultefileRuntimeException.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\AbstractJPAHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\interceptor\GenericInterceptor.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\EnvironmentPK.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\AbstractJPAHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\PersistenceHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\mock\MockPersistenceHelper.class
                     [aopc] [no comp needed] C:\workspace\multefile-core-dev\offcard\research\AOPUnitTestPOC\aopclasses\com\ecebs\unittest\aop\entitymodel\Revision.class
                

                 

                Seems a bit strange!

                 

                In the past I have been able to use the call and withincode combination, however the java class defined in the withincode was not a JUnit test.

                • 5. Re: withincode from JUnit test not working
                  flavia.rainone

                  nizzy wrote:

                   

                  In the past I have been able to use the call and withincode combination, however the java class defined in the withincode was not a JUnit test.

                  How about other calls that match the call pointcut (without within/withincode)? Calls made from other points of your code should be intercepted.

                   

                  If there isn't such a call, I would replace your call in the test class:

                   

                  public class MyTest extends TestCase{
                  
                  
                   public void testSomething()
                    {
                       pojo.call();
                    }
                  }
                  

                   

                   

                  By something like this:

                   

                  public class MyTest extends TestCase
                  {
                  
                     public void testSomething()
                     {
                         Caller.call();
                     }
                  }
                  
                  
                  public Caller
                  {
                     public static void call()
                     {
                       pojo.call();
                     }
                  }
                  

                   

                  I.e., I would move that call to another class, and see if JBoss AOP intercepts it. If it doesn't, it definitely has nothing to do with being inside a test class. And, since we have tests for all pointcut types, I would guess that the problem is somewhere else in that case.

                  • 6. Re: withincode from JUnit test not working
                    flavia.rainone

                    Alan,

                     

                    Taking a look at your older post, I see that the bean you're mentioning in the pointcut is an EJB session bean, is that right?

                     

                    If it is, then I may know why is your pointcut not picking the call. When a call is made to a session bean, you are actually calling the session bean stub, whose type is unknown but implements the bean's interface. For that reason, I think that if you use instanceof{session interface type} as the class name in the call pointcut, it will work:

                     

                    <bind pointcut="call(public void $instanceof{<fill in with the bean interface here>}->createObject(..))">
                     <advice name="throwMultefileException" aspect="com.ecebs.unittest.aop.aspect.ExceptionInjector" />
                    </bind>
                    
                    

                     

                    Let me know if that solves your problem!

                    • 7. Re: withincode from JUnit test not working
                      nizzy

                      Flavio your a genius, well as far as I'm concerned anyway,

                       

                      In JUnit test (ExampleManagerBeanTest) changed;

                       

                      private ExampleManager man;
                      

                       

                      where ExampleManager is the remote interface of the ExampleManagerBean to;

                       

                      private ExampleManagerBean man;
                      

                       

                      And that seemed to do the trick. The exception was thrown as I would have expected. I will also try the alteration to the pointcut you suggested, however the quck check was enough for now. Normally when testing session beans outside the container we explicitly create instance of the class directly, and do not use the interface.

                       

                      It always simple when you know the solution,

                       

                      Thanks for the help, I simply did not know what else to try!

                      • 8. Re: withincode from JUnit test not working
                        flavia.rainone

                        nizzy wrote:

                         

                        And that seemed to do the trick. The exception was thrown as I would have expected. I will also try the alteration to the pointcut you suggested, however the quck check was enough for now. Normally when testing session beans outside the container we explicitly create instance of the class directly, and do not use the interface.

                         

                        It always simple when you know the solution,

                         

                        Thanks for the help, I simply did not know what else to try!

                        I'm glad it worked!