Announcement Announcement Module
Collapse
No announcement yet.
Clearing the context to avoid out of memory when using JUnit test Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Clearing the context to avoid out of memory when using JUnit test

    I use JUnit tests from within Eclipse to test my code. My problem is that each test sets up a new applicationContext and don't seem to be able to get rid of it by just nulling the reference. So I quickly get a heck of a lot of instances of objects and I run out of memory. (Everything becomes REALLY slow) Is there a clever way to get rid of all Spring objects from memory when I am done with a test and goes on to the next one?

    // Jonathan

  • #2
    Are you using your own test mechanism or use the test classes provided by Spring? I strongly suggest you use the latter.

    Comment


    • #3
      Originally posted by mdeinum View Post
      Are you using your own test mechanism or use the test classes provided by Spring? I strongly suggest you use the latter.
      Are there test classes provided by Spring? Will they help with this? my tests looks a little bit like this:

      Code:
      package net.bioclipse.lis.tests.daos;
      
      import java.util.ArrayList;
      import java.util.List;
      
      import org.junit.Test;
      
      import static org.junit.Assert.*;
      
      import net.bioclipse.lis.genericDAO.IUserDAO;
      import net.bioclipse.lis.pojos.User;
      
      /**
       * Tests all the functionality of the <code>UserDAO</code>
       * 
       * @author jonathan
       *
       */
      public class UserDAOTest extends AbstractGenericDAOTest {
      	
      	public IUserDAO getDAO(){
      		return (IUserDAO)dao;
      	}
      	
      	public UserDAOTest() {
      		super("userDAO");
      	}
      
      	/**
      	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#delete(long)}.
      	 */
      	@Test
      	public void testDelete() {
      		User user   = User.createUser("Delete Tester");
      		assertFalse(user.isDeleted());
      		getDAO().save(user);
      		
      		session.flush();
      		session.clear();
      		
      		getDAO().delete(user.getId());
      		
      		session.flush();
      		session.clear();
      		
      		User deleted = getDAO().getById(new Long(user.getId()));
      		assertTrue(deleted.isDeleted());
      	}
      
      	/**
      	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#getAll()}.
      	 */
      	@Test
      	public void testGetAll() {
      		
      		User user1 = User.createUser("Getall Tester1");
      		User user2 = User.createUser("Getall Tester2");
      		getDAO().save(user1);
      		getDAO().save(user2);
      		
      		session.flush();
      		session.clear();
      		
      		List list = getDAO().findAll();
      		assertTrue(list.contains(user1));
      		assertTrue(list.contains(user2));
      	}
      
      	
      	/**
      	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#save(net.bioclipse.lis.pojos.User)}.
      	 */
      	@Test
      	public void testSave() {
      		User user = User.createUser("Save Tester");
      		getDAO().save(user);
      		
      		session.flush();
      		session.clear();
      		
      		User savedUser = getDAO().getById(user.getId());
      		assertEquals(user, savedUser);
      		assertNotSame(user, savedUser);
      	}
      	
      	/**
      	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#getById(long)}.
      	 */
      	@Test
      	public void testGetById() {
      		User user = User.createUser("Getbyid Tester");
      		getDAO().save(user);
      		
      		session.flush();
      		session.clear();
      		
      		User savedUser = getDAO().getById(new Long(user.getId()));
      		assertEquals(user, savedUser);
      		assertNotSame(user, savedUser);		
      	}
      	
      	@Test
      	public void testFindByName() {
      		User user = User.createUser("findMe");
      		getDAO().save(user);
      		
      		session.flush();
      		session.clear();
      		
      		ArrayList<User> retrievedUsers = (ArrayList<User>)getDAO().findByName("findMe");
      		User savedUser = retrievedUsers.get(0);
      		assertEquals(user, savedUser);
      		assertNotSame(user, savedUser);	
      	}
      }
      Code:
      public abstract class AbstractGenericDAOTest {
      
      	protected IGenericDAO dao;
      	protected Session     session;
      	protected ApplicationContext context;
      //snip
      public AbstractGenericDAOTest(String DAOBeanName){
      		context = new ClassPathXmlApplicationContext("applicationContext.xml");		
      		dao = (IGenericDAO)context.getBean(DAOBeanName);
      		session = SessionFactoryUtils.getSession(dao.getSessionFactory(),true);
      		
      	}
      
      @Before
      	public void setUp() throws Exception {
      
      		net.bioclipse.lis.tests.Tools.newCleanDatabase();
      		TransactionSynchronizationManager.bindResource(dao.getSessionFactory(), new SessionHolder(session));
      
      //snipp
      
      @After
      	public void tearDown(){
      		
      		TransactionSynchronizationManager.unbindResource(dao.getSessionFactory());
      		SessionFactoryUtils.releaseSession(session, dao.getSessionFactory());
      And they works fine except for when I run alot of them at the same time...

      Comment


      • #4
        Spring provides test classes for well everything you did on your own. The Spring test classes will also inject dependencies in your testclass! Also it will only load the applicationcontext once instead of before every test method, it also takes care of transaction management for you, instead of doing it yourself.

        Read chapter 8 of the reference guide, which covers testing. You also might want to checkout the [url=http://www.springframework.org/docs/api/org/springframework/test/AbstractSpringContextTests.html]javadocs[url] regarding the test classes.

        The rewrite in your case would be

        Code:
        public abstract class AbstractGenericDAOTest extends org.springframework.test.AbstractTransactionalSpringContextTests{
        
          private static final String[] LOCATIONS = {"applicationContext.xml"}
        
          public AbstractGenericDAOTest() {
            setAutowireMode(AUTOWIRE_BY_NAME);
          }
        
          protected String[] getConfigLocations() {
            return LOCATIONS;
          }
        }
        
        package net.bioclipse.lis.tests.daos;
        
        import java.util.ArrayList;
        import java.util.List;
        
        import org.junit.Test;
        
        import static org.junit.Assert.*;
        
        import net.bioclipse.lis.genericDAO.IUserDAO;
        import net.bioclipse.lis.pojos.User;
        
        /**
         * Tests all the functionality of the <code>UserDAO</code>
         * 
         * @author jonathan
         *
         */
        public class UserDAOTest extends AbstractGenericDAOTest {
        	
        	private GenericDao dao;
        	
        	//Spring will inject this for you.
        	public void setIUserDao(GenericDao dao){
        		return this.dao=dao;
        	}
        	
        	public UserDAOTest() {
        		super();
        	}
        
        	/**
        	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#delete(long)}.
        	 */
        	@Test
        	public void testDelete() {
        		User user   = User.createUser("Delete Tester");
        		assertFalse(user.isDeleted());
        		dao.save(user);
                setComplete()
                endTransaction();
                startTransaction();		
        		
        		dao.delete(user.getId());
        		
                setComplete()
                endTransaction();
                startTransaction();		
        		
        		User deleted = dao.getById(new Long(user.getId()));
        		assertTrue(deleted.isDeleted());
        	}
        
        	/**
        	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#getAll()}.
        	 */
        	@Test
        	public void testGetAll() {
        		
        		User user1 = User.createUser("Getall Tester1");
        		User user2 = User.createUser("Getall Tester2");
        		dao.save(user1);
        		dao.save(user2);
                setComplete()		
                endTransaction();
                startTransaction();		
        		
        		List list = dao.findAll();
        		assertTrue(list.contains(user1));
        		assertTrue(list.contains(user2));
        	}
        
        	
        	/**
        	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#save(net.bioclipse.lis.pojos.User)}.
        	 */
        	@Test
        	public void testSave() {
        		User user = User.createUser("Save Tester");
        		dao.save(user);
        	        setComplete()	
                endTransaction();
                startTransaction();		
        		
        		User savedUser = dao.getById(user.getId());
        		assertEquals(user, savedUser);
        		assertNotSame(user, savedUser);
        	}
        	
        	/**
        	 * Test method for {@link net.bioclipse.lis.daos.UserDAO#getById(long)}.
        	 */
        	@Test
        	public void testGetById() {
        		User user = User.createUser("Getbyid Tester");
        		dao.save(user);
        	        setComplete()	
                endTransaction();
                startTransaction();		
        		
        		User savedUser = dao.getById(new Long(user.getId()));
        		assertEquals(user, savedUser);
        		assertNotSame(user, savedUser);		
        	}
        	
        	@Test
        	public void testFindByName() {
        		User user = User.createUser("findMe");
        		dao.save(user);
        	        setComplete()	
                endTransaction();
                startTransaction();		
        		
        		ArrayList<User> retrievedUsers = (ArrayList<User>)dao.findByName("findMe");
        		User savedUser = retrievedUsers.get(0);
        		assertEquals(user, savedUser);
        		assertNotSame(user, savedUser);	
        	}
        }
        Last edited by Marten Deinum; Jul 3rd, 2007, 08:09 AM.

        Comment


        • #5
          Thanks I'll have to test that and see if it solves my problems

          // Jonathan

          Comment


          • #6
            Your welcome, I give no garantues as I simply typed it in the edit box . Hmm I wonder is knowing the Spring API from the top of your head bad?!

            Comment


            • #7
              Originally posted by Jonathan Alvarsson View Post
              Thanks I'll have to test that and see if it solves my problems

              // Jonathan
              There is one small issue - Spring test classes are JUnit 3.8.1 based and you have strived to use JUnit 4.x. If using of Junit 4 is important for you, then start not from using Spring test classes, but just by converting application context in your tests into the static field. It should be enough to solve your problem.

              BTW, I vaguely remember that some project exists for porting Spring test classes to JUnit4, but I do not remeber details. Try to search this forum, it was discussed here some time ago.

              Comment


              • #8
                Oops, missed that bit .

                Spring 2.1 provides JUnit 4 integration. However the lack of integration support for JUnit and/or TestNG led us to unitils. Next to that it also provides DBUnit integration and some other convenience tools.

                Comment


                • #9
                  //Spring will inject this for you.
                  public void setIUserDao(GenericDao dao){
                  return this.dao=dao;
                  }
                  Based upon what can Spring make this sort of injection? There is not any xml definitions to work by...

                  I need something like this:
                  Code:
                          <bean id="userDAO" parent="abstractDAO">
                          <property name="proxyInterfaces">
                          	<value>net.bioclipse.lis.genericDAO.IUserDAO</value>
                      	</property>
                      	<property name="target">
                          	<bean parent="abstractDAOTarget">
                              	<constructor-arg>
                                  	<value>net.bioclipse.lis.pojos.User</value>
                              	</constructor-arg>
                          	</bean>
                      	</property>
                  	</bean>
                  See: <http://www.ibm.com/developerworks/java/library/j-genericdao.html>

                  Comment


                  • #10
                    Originally posted by mdeinum View Post
                    Oops, missed that bit .

                    Spring 2.1 provides JUnit 4 integration. However the lack of integration support for JUnit and/or TestNG led us to unitils. Next to that it also provides DBUnit integration and some other convenience tools.
                    Spring 2.1 is not yet here (it even not reached RC stage).
                    And my first impression of unutils was not that good, but I have not used them, just have taken a look.

                    Really, I'm happy with JUnit 3.8.1 and do not see (for me) any real need in the migration to JUnit 4 or TestNG.

                    Comment


                    • #11
                      There is one small issue - Spring test classes are JUnit 3.8.1 based and you have strived to use JUnit 4.x. If using of Junit 4 is important for you, then start not from using Spring test classes, but just by converting application context in your tests into the static field. It should be enough to solve your problem.
                      JUnit 4 is not really important since I made the migration today as an attempt to solve my problem however your tip of using one static application context solved my problems so I think I will continue using JUnit 4. I mean it probably is the future, right?
                      Thanks for the help.

                      BTW, I vaguely remember that some project exists for porting Spring test classes to JUnit4, but I do not remeber details. Try to search this forum, it was discussed here some time ago.
                      But they will sooner or later turn up in Spring right? I think I'll just wait. For now this solution seems to work...

                      Comment


                      • #12
                        Originally posted by Jonathan Alvarsson View Post
                        JUnit 4 is not really important since I made the migration today as an attempt to solve my problem however your tip of using one static application context solved my problems so I think I will continue using JUnit 4. I mean it probably is the future, right?
                        Thanks for the help.



                        But they will sooner or later turn up in Spring right? I think I'll just wait. For now this solution seems to work...

                        Yes, as mdenium has remarked it is already in Spring 2.1 indeed. I do not know exact roadmap for 2.1, but I hope, that it would be ready till end of year.

                        IF you ask me where to migrate - JUnit 4 or TestNG I would select latter, but Spring has selected former.

                        Comment


                        • #13
                          Originally posted by Jonathan Alvarsson View Post
                          Based upon what can Spring make this sort of injection? There is not any xml definitions to work by...
                          As a default Spring injects references based on type on your testclasses, in your generic test class I changed it to ByName. However judging by your xml snippet you will need to change the setter to setUserDAO (based on the property name). Or change the dependency injection to by type, make the property dao protected and change the type to IUserDao that way Spring will inject it to.

                          Comment

                          Working...
                          X