Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: Single context loading for all test classes

  1. #1
    Join Date
    Aug 2004
    Location
    Los Angeles, USA
    Posts
    62

    Default Single context loading for all test classes

    I would like to initialize my applicaton context only once for all of my test classes. I have found some posts that propose static initializations but this only works within one test class. Other test classes will load a new application context.

    Is there any best practise for bootstrapping the application context only once?

  2. #2
    Join Date
    Aug 2004
    Location
    San Mateo, CA
    Posts
    1,265

    Default

    I'm working on a solution that will use a static, but will use a key so that it applies correctly across all classes. I'm currently using this with excellent results in a consulting engagement, and will check it into the mock tree next week, and release it as part of Spring 1.2.

    It also supports running tests inside a transaction that's rolled back automatically. We've found this a huge productivity gain for integration testing.

    I'll try to remember to post here when I've checked it in...
    Rod Johnson - GM, SpringSource Division, VMware
    http://www.springsource.com
    Spring From the Source

  3. #3
    Join Date
    Aug 2004
    Location
    San Mateo, CA
    Posts
    1,265

    Default

    I've now committed my support classes, including the transactional capability I mentioned. See the org.springframework.test package in the /mock tree in CVS.

    Feedback welcome.
    Rod Johnson - GM, SpringSource Division, VMware
    http://www.springsource.com
    Spring From the Source

  4. #4
    Join Date
    Aug 2004
    Location
    Los Angeles, USA
    Posts
    62

    Default

    ok. thanks. I'll give it a shot and let you know.

  5. #5
    Join Date
    Aug 2004
    Location
    (eastern) North Carolina
    Posts
    17

    Default

    Below is the latest version of something I posted a little while ago.

    http://forum.springframework.org/sho...902&highlight=

    You need to call initialize() in setup of each class (in a test suite), but the context is only loaded once if the list of context files never changes. And if list changes that is ok too; context will be loaded if the file list differs from previous test class.

    I have found some posts that propose static initializations but this only works within one test class.
    ContextTestCase will load context only once for entire test suite.

    Other test classes will load a new application context.
    Not if all classes in your test suite inherit from ContextTestCase and the context file list is the same in initialize() method call of each.


    Here is latest version:

    Code:
    import java.util.StringTokenizer;
    import junit.framework.TestCase;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * A JUnit TestCase extension that simplifies integration testing by making 
     * available a Spring application context.  This class short-circuits the 
     * 'set all instance variables null before every test method' mechanism in 
     * favor of loading Spring environment only once before executing any test 
     * methods.
     */
    public class ContextTestCase extends TestCase 
    {
      private static String[] contextFiles = null;
      private static ApplicationContext context = null;
      
      protected final Object getBean( String bean )
      {
        return context.getBean(bean);
      }
    
      protected final ApplicationContext getContext()
      {
        return context;
      }
      
      /**
       * Alternate form to initialize/load context
       * @param xmlFiles in comma delimited string
       */
      protected final void initialize( String xmlFiles )
        throws Exception
      {
        String[] contextFiles = toStringArray( xmlFiles );
        initialize( contextFiles );
      }
      
      /**
       * @param xmlFiles  context files that specify objects available 
       *                  in Spring application environment.
       */
      protected final void initialize( String[] xmlFiles ) 
         throws Exception
      {
        synchronized (ContextTestCase.class) {
          if( context == null || !same( xmlFiles, contextFiles ) ) {
            contextFiles = xmlFiles;
            context = new ClassPathXmlApplicationContext( xmlFiles ); // load context
            
            StringBuffer msg = new StringBuffer("<<< CONTEXT LOADED >>> [");
            for( int i = 0; i < xmlFiles.length; i++ ) {
              if ( i > 0 ) { msg.append(" "); }
              msg.append( xmlFiles[i] );
            }
            msg.append("] IN class='");
            msg.append( this.getClass().getName() );
            msg.append("'");
            System.out.println( msg.toString() );
          }
        }
      }
      
      /*
       * Are String arrays the same or different?
       */
      private static boolean same( String[] files1, String[] files2 )
      {
        boolean ret = true;
        ret = files1 != null && files2 != null && files1.length == files2.length; 
        // true if both not null & same length arrays
        
        // loop stops if ret==false
        for( int i = 0; ret && i < files1.length; i++ ) { 
          ret = files1[i].equals( files2[i] );
        }
        return ret;
      }
      
      /*
       * Convert comma delimited string into String array.
       */
      private static String[] toStringArray( String listing )
      {
        String[] ret = null;
        
        StringTokenizer t = new StringTokenizer( listing, "," );
        final int count = t.countTokens();
        ret = new String[count];
        
        for( int i = 0; i < count; i++ ) {
          ret[i] = t.nextToken().trim();
        }
        return ret;
      }
    }
    And your descendent class will have code something like this:

    Code:
      MyClass instanceRef = null;
    
      public void setUp() throws Exception 
      { 
        initialize( "contextFile1.xml,contextFile2.xml" ); 
        instanceRef = (MyClass)getBean("myClassBean"); 
      }
    Last edited by Rod Johnson; Jan 18th, 2006 at 10:56 AM.

  6. #6
    Join Date
    Aug 2004
    Location
    Los Angeles, USA
    Posts
    62

    Default

    That works within a testsuite but the point is to make something run outside a testsuite (within an Ant build e.g.)

  7. #7
    Join Date
    Aug 2004
    Location
    (eastern) North Carolina
    Posts
    17

    Default

    You are saying following does not work?

    <junit fork="yes" forkmode="once">
    <test fork="no" ....
    etc....

    Where all the tests are defined in same way.

    If you can get all the tests to run in same JVM then context should be loaded once as desired.

    Regards, Jim

  8. #8
    Join Date
    Aug 2004
    Location
    Los Angeles, USA
    Posts
    62

    Default

    I have tried Rod's test case and it didn't work with a standard Maven build that executes the tests. Furthermore even within Eclipse the testcases submitted in CVS reload the application context with each test class. Feester's approach works in Eclipse but doesn't in Maven. I'll first look at what's wrong with Rod's test cases (might be me not using them correctly) then when it works in Eclipse, I'll try to see if there's something wrong with Maven's test plugin.

    Rod,

    Could you add a very simple test class that illustrates the usage of your test classes? That might help me figuring out what goes wrong.

  9. #9
    Join Date
    Aug 2004
    Location
    (eastern) North Carolina
    Posts
    17

    Default

    I don't know anything about Maven. Does Maven build run via Ant?

    If so, and even if not, I believe the problem is that each test class is getting forked into a new JVM.

    If Ant is involved, take a look at the documentation for junit and test tasks and their fork and forkmode attributes.

    http://ant.apache.org/manual/OptionalTasks/junit.html

  10. #10
    Join Date
    Aug 2004
    Location
    Los Angeles, USA
    Posts
    62

    Default

    Maven uses Ant underneath. I had a quick look at the way Maven calls Ant and normally, by default, it does not fork unit tests. I'll have to dig deeper into this because I suspect that Maven is actually forking test classes.

Similar Threads

  1. Error loading context: unknown protocol: jndi
    By graeder in forum Container
    Replies: 12
    Last Post: Oct 27th, 2005, 09:07 AM
  2. Replies: 2
    Last Post: Oct 13th, 2005, 02:47 PM
  3. Loading context from custom classloader
    By mgarber in forum Container
    Replies: 6
    Last Post: Oct 13th, 2005, 03:17 AM
  4. Loosing my SecureContext
    By sklakken in forum Security
    Replies: 3
    Last Post: Jul 21st, 2005, 01:44 PM
  5. Stack Overflow
    By rayho222 in forum Container
    Replies: 6
    Last Post: May 17th, 2005, 03:42 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •