2. Code Example

The @RunWith annotation is part of JUnit 4 and is set to use SpringJUnit4ClassRunner to run the unit test. The other annotations, except for @Test, are Spring annotations. @ContextConfiguration initializes the Spring context and by default looks for a Spring XML file in the same package as the unit test with the file name the same as the class with '-context.xml' as a suffix (ex: PersonDaoTransactionUnitTest-context.xml.). @TransactionConfiguration and @Transactional configure transactions for the tests.

The method with @Test is the main test method which saves a person in a transaction. The method with @BeforeTransaction is run before the transaction starts and the method with @AfterTransaction is run after the transaction ends. They both use SimpleJdbcTemplate to directly check the database and avoid any caching Hibernate might be performing.

Example 1. PersonDaoTransactionUnitTest

                
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration
@Transactional
public class PersonDaoTransactionUnitTest extends AbstractTransactionalJUnit4SpringContextTests {

    final Logger logger = LoggerFactory.getLogger(PersonDaoTransactionUnitTest.class);
    
    protected static int SIZE = 2;
    protected static Integer ID = new Integer(1);
    protected static String FIRST_NAME = "Joe";
    protected static String LAST_NAME = "Smith";
    protected static String CHANGED_LAST_NAME = "Jackson";

    @Autowired
    protected PersonDao personDao = null;
    
    /**
     * Tests that the size and first record match what is expected 
     * before the transaction.
     */
    @BeforeTransaction
    public void beforeTransaction() {
        testPerson(true, LAST_NAME);
    }

    /**
     * Tests person table and changes the first records last name.
     */
    @Test
    public void testHibernateTemplate() throws SQLException {
        assertNotNull("Person DAO is null.", personDao);
        
        Collection<Person> lPersons = personDao.findPersons();
        
        assertNotNull("Person list is null.", lPersons);
        assertEquals("Number of persons should be " + SIZE + ".", SIZE, lPersons.size());
        
        for (Person person : lPersons) {
            assertNotNull("Person is null.", person);
                        
            if (ID.equals(person.getId())) {                
                assertEquals("Person first name should be " + FIRST_NAME + ".", FIRST_NAME, person.getFirstName());
                assertEquals("Person last name should be " + LAST_NAME + ".", LAST_NAME, person.getLastName());
                
                person.setLastName(CHANGED_LAST_NAME);
                
                personDao.save(person);
            }
        }
    }

    /**
     * Tests that the size and first record match what is expected 
     * after the transaction.
     */
    @AfterTransaction
    public void afterTransaction() {
        testPerson(false, LAST_NAME);
    }

    /**
     * Tests person table.
     */
    protected void testPerson(boolean beforeTransaction, String matchLastName) {
        List<Map<String, Object>> lPersonMaps = simpleJdbcTemplate.queryForList("SELECT * FROM PERSON");

        assertNotNull("Person list is null.", lPersonMaps);
        assertEquals("Number of persons should be " + SIZE + ".", SIZE, lPersonMaps.size());

        Map<String, Object> hPerson = lPersonMaps.get(0);

        logger.debug((beforeTransaction ? "Before" : "After") + " transaction.  " + hPerson.toString());
            
        Integer id = (Integer)hPerson.get("ID");
        String firstName = (String)hPerson.get("FIRST_NAME");
        String lastName = (String)hPerson.get("LAST_NAME");
        
        if (ID.equals(id)) {                
            assertEquals("Person first name should be " + FIRST_NAME + ".", FIRST_NAME, firstName);
            assertEquals("Person last name should be " + matchLastName + ".", matchLastName, lastName);
        }
    }
    
}