Announcement Announcement Module
Collapse
No announcement yet.
verify delete in unit test Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • verify delete in unit test

    I have a dao with a delete method that uses hibernate, like this:
    Code:
        public void delete(Long id) {
            Department department = new Department(id);
            getHibernateTemplate().delete(department);
        }
    I would like to write a unit test that verifies that the delete method works, but I would like it to not acutally change the state of the database, i.e. rollback at the end of the method. So I am using AbstractTransactionalDataSourceSpringContextTests like this:
    Code:
        public void testDelete() {
    
            assertEquals("There should be one department with id = 1",1,
                jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
            
            
            dao.delete(1L);
            
            assertEquals("There should be no departments with id = 1",0,
                jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
            
        }
    But the test fails because the second query with the jdbc template still returns 1. I assume this is because the jdbc template is looking at the current committed state of the database, which does not include whatever uncommitted changes hibernate has made. So then I tried it this way:
    Code:
        public void testDelete() {
            dao.delete(1L);
            assertNull("There should be no departments with id = 1",dao.get(1L));
        }
    where the dao get method looks like this:
    Code:
        public Department get(Long id) {
            return (Department)getHibernateTemplate().get(Department.class,id);
        }
    The testDelete method throws this exception:
    Code:
    org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException: The object with that id was deleted: [sample.model.Department#1]; nested exception is org.hibernate.ObjectDeletedException: The object with that id was deleted: [sample.model.Department#1]
    org.hibernate.ObjectDeletedException: The object with that id was deleted: [sample.model.Department#1]
    So my thinking now if that maybe I should just use this method and catch the HibernateObjectRetrievalFailureException. If that exception is thrown, then the test passes. Is that the best way to write a unit test that deletes an object, verifies that it was in fact deleted, and then rolls the transaction back? If not, does anyone have a better way?

  • #2
    You need to flush the hibernate session after you all dao.delete() in order to update the database (the transaction will still rollback).

    Comment


    • #3
      Originally posted by gcosgrave
      You need to flush the hibernate session after you all dao.delete() in order to update the database (the transaction will still rollback).
      Doesn't the hibentate template take care of that for me?

      Comment


      • #4
        I modifed the dao method to look like this:
        Code:
            public void delete(Long id) {
                Department department = new Department(id);
                getHibernateTemplate().delete(department);
                getHibernateTemplate().flush();
            }
        And now both versions of the testDelete from the original post pass. But the javadocs for HibernateTemplate.flush() say:

        Only invoke this for selective eager flushing, for example when JDBC code needs to see certain changes within the same transaction. Else, it's preferable to rely on auto-flushing at transaction completion.

        So I shouldn't I avoid calling that in my dao methods? Calling it just to make my unit tests pass seems like a bad idea.

        Comment


        • #5
          No, you should flush within your unit tests, not the DAO method

          Comment


          • #6
            Originally posted by yatesco
            No, you should flush within your unit tests, not the DAO method
            Ok, so how do I flush within the unit test?

            Comment


            • #7
              I have done this by configuring a HibernateFlusher bean in the application context using the same sessionFactory as the dao. All you then need to do is load it and call flush.
              Code:
              import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
              
              public class HibernateFlusher extends HibernateDaoSupport  {
              
                  public void flush() {
                      getHibernateTemplate().flush();
                  }
              
              }

              Comment


              • #8
                Ok, so I added this method to my abstract class that my dao tests extend:
                Code:
                    private HibernateTemplate hibernateTemplate;
                    ...
                    protected void flush() {
                        //Initialize Hibernate Template if Necessary
                        if(hibernateTemplate == null) {
                            hibernateTemplate = new HibernateTemplate((SessionFactory)
                                getContext("hibernate-context.xml").getBean("SessionFactory"));
                        }
                        hibernateTemplate.flush();
                    }
                Then within my tests, I just call it like this:
                Code:
                    public void testDelete() {
                
                        assertEquals("There should be one department with id = 1",1,
                            jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
                        
                        dao.delete(1L);
                        flush();
                        
                        assertEquals("There should be no departments with id = 1",0,
                            jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
                        
                    }
                And this works and my tests pass. So is this the best way to test DAO methods, without re-populating the data to a known state before and after each test with something like DbUnit? If so, would it be a good idea to add something like this to AbstractTransactionalDataSourceSpringContextTests?

                Comment


                • #9
                  Originally posted by paul.barry
                  Ok, so I added this method to my abstract class that my dao tests extend:
                  Code:
                      private HibernateTemplate hibernateTemplate;
                      ...
                      protected void flush() {
                          //Initialize Hibernate Template if Necessary
                          if(hibernateTemplate == null) {
                              hibernateTemplate = new HibernateTemplate((SessionFactory)
                                  getContext("hibernate-context.xml").getBean("SessionFactory"));
                          }
                          hibernateTemplate.flush();
                      }
                  Then within my tests, I just call it like this:
                  Code:
                      public void testDelete() {
                  
                          assertEquals("There should be one department with id = 1",1,
                              jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
                          
                          dao.delete(1L);
                          flush();
                          
                          assertEquals("There should be no departments with id = 1",0,
                              jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
                          
                      }
                  Paul, just to reassure you, I did exactly what you did. That is, I also added a flush() method to my abstract dao test class and I also use the same pattern as you: 1) call dao method, 2) call flush, then 3) do assertions with jdbcTemplate.

                  Originally posted by paul.barry
                  And this works and my tests pass. So is this the best way to test DAO methods, without re-populating the data to a known state before and after each test with something like DbUnit? If so, would it be a good idea to add something like this to AbstractTransactionalDataSourceSpringContextTests?
                  It works for me. . BTW, you should not have to use DbUnit because AbstractTransactionalDataSourceSpringContextTests will automatically roll back any changes you make to the database during your test run. That is, at the start of each test method (e.g. testDelete()), it starts a transaction and then at the end of each test method, it rolls back the transaction. You can override this automatic rollback behaviour (see setComplete() and setDefaultRollback()) but the default is to rollback. In fact, because of this rollback feature of AbstractTransactionalDataSourceSpringContextTests, I personally can't see any use for DbUnit anymore, especially since the automatic rollback is very fast.

                  Comment


                  • #10
                    Please ignore.

                    Comment


                    • #11
                      Originally posted by wpoitras
                      Please ignore.
                      ??? Ignore what, the thread? Why

                      Comment


                      • #12
                        Not the thread, my message. I had typed a reply and later realized I hadn't read the thread carefully enough.

                        Comment


                        • #13
                          BTW, you should not have to use DbUnit because AbstractTransactionalDataSourceSpringContextTests will automatically roll back any changes you make to the database during your test run. That is, at the start of each test method (e.g. testDelete()), it starts a transaction and then at the end of each test method, it rolls back the transaction. You can override this automatic rollback behaviour (see setComplete() and setDefaultRollback()) but the default is to rollback. In fact, because of this rollback feature of AbstractTransactionalDataSourceSpringContextTests, I personally can't see any use for DbUnit anymore, especially since the automatic rollback is very fast.
                          I can still see a use for DbUnit in my current situation.

                          You're still quite correct that AbstractTransactionalDataSourceSpringContextTests makes sure that the JUnit tests themselves don't do any harm to the test data set.

                          But if your app does not have complete control over the test database, and there's a chance that other users will modify the data it contains, then DbUnit can be valuable to make sure that the test records you need appear in the database before you run JUnit.

                          %

                          Comment


                          • #14
                            This post was made almost a year ago. I was wondering if other people are using this same strategy now.

                            thanks,
                            Mike


                            Originally posted by paul.barry
                            Ok, so I added this method to my abstract class that my dao tests extend:
                            Code:
                                private HibernateTemplate hibernateTemplate;
                                ...
                                protected void flush() {
                                    //Initialize Hibernate Template if Necessary
                                    if(hibernateTemplate == null) {
                                        hibernateTemplate = new HibernateTemplate((SessionFactory)
                                            getContext("hibernate-context.xml").getBean("SessionFactory"));
                                    }
                                    hibernateTemplate.flush();
                                }
                            Then within my tests, I just call it like this:
                            Code:
                                public void testDelete() {
                            
                                    assertEquals("There should be one department with id = 1",1,
                                        jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
                                    
                                    dao.delete(1L);
                                    flush();
                                    
                                    assertEquals("There should be no departments with id = 1",0,
                                        jdbcTemplate.queryForInt("SELECT COUNT(*) FROM departments where id = 1"));        
                                    
                                }
                            And this works and my tests pass. So is this the best way to test DAO methods, without re-populating the data to a known state before and after each test with something like DbUnit? If so, would it be a good idea to add something like this to AbstractTransactionalDataSourceSpringContextTests?
                            Last edited by mmasters; Aug 16th, 2006, 05:47 PM.

                            Comment


                            • #15
                              How to do flush If I don't have hibernate-config.xml

                              In my case,
                              I am using hibernate --> Sprint --> AndroMDA
                              And I am stuck with this issue as well, I see no otherway than catching this exception(HibernateObjectRetrievalFailureException )
                              Anyone got work around in above env?

                              Comment

                              Working...
                              X