J2EE Without the Application Server
Pages: 1, 2, 3, 4, 5, 6, 7
Step 3: Testing the BankDAO
Let's test our code, then. (Extreme programmers would write the tests first, but for the sake of clarity, we delayed this step until now.) A simple unit test can be found below. This test can be run from within your standard IDE; no application server is involved. The unit test is designed as a mini-application on its own: it uses Spring to retrieve a configured Bank object to test (this is done in the setUp method). Note that the test uses explicit transaction demarcation: a transaction is started before each test and rollback is forced at the end of each test. This is a handy way to minimize the effects of testing on the database data.
package jdbc;
import com.atomikos.icatch.jta.UserTransactionImp;
import junit.framework.TestCase;
import java.io.FileInputStream;
import java.io.InputStream;
import org.springframework.beans.factory.xml.XmlBeanFactory;
public class BankTest extends TestCase
{
private UserTransactionImp utx;
private Bank bank;
public BankTest ( String name )
{
super ( name );
utx = new UserTransactionImp();
}
protected void setUp()
throws Exception
{
//start a new transaction
//so we can rollback the
//effects of each test
//in teardown!
utx.begin();
//open bean XML file
InputStream is =
new FileInputStream("config.xml");
//the factory is Spring's entry point
//for retrieving the configured
//objects from the XML file
XmlBeanFactory factory =
new XmlBeanFactory(is);
bank = ( Bank ) factory.getBean ( "bank" );
bank.checkTables();
}
protected void tearDown()
throws Exception
{
//rollback all DBMS effects
//of testing
utx.rollback();
}
public void testBank()
throws Exception
{
int accNo = 10;
long initialBalance = bank.getBalance ( accNo );
bank.withdraw ( accNo , 100 );
long newBalance = bank.getBalance ( accNo );
if ( ( initialBalance - newBalance ) != 100 )
fail ( "Wrong balance after withdraw: " +
newBalance );
}
}
We will need JTA transactions to make sure that both the JMS and the JDBC are performed atomically. In general, you should consider JTA/XA whenever two or more connectors are needed, such as JMS and JDBC in our case. Spring doesn't offer JTA transactions by itself; it needs a JTA implementation and normally delegates to an application server to do that. However, we are using an embeddable JTA implementation that works on any J2SE platform.
The resulting architecture is show below in Figure 3. The white boxes represent our application code.

Figure 3. Architecture for the test
As you can see, the following happens when we run our test:
- The
BankTeststarts a new transaction. - The test then retrieves the object named
bankfrom the Spring runtime. This step triggers Spring's creation and initialization process. - The test calls the
bank's method(s). - The
bankinvokes the object nameddatasource, which it has received from Spring via itssetDataSourcemethod. - The
datasourceis JTA-enabled and interacts with the JTA implementation to register with the current transaction. - JDBC statements interact with the accounts database.
- When the method returns, the test calls
rollbackfor the transaction. - JTA remembers the
datasourceand instructs it to roll back.