Java Reference
In-Depth Information
of concurrent connections), it's a good practice to open it at the beginning of the
tests and close it at the end. Alternatively, if a connection pool was used instead, these
methods could be defined at @Before / @After, respectively.
At D , connection is a just a regular JDBC connection ( java.sql.Connection ),
but dbunitConnection is a DbUnit IDatabaseConnection instance. DbUnit uses
IDatabaseConnection to encapsulate access to the database, and it provides imple-
mentations for the most common databases. The advantage of using a specialized
IDatabaseConnection implementation ( HsqldbDatabaseConnection in this case)
rather than the generic one ( DatabaseConnection ) is that it can handle nuances spe-
cific to that database, like conversion between nonstandard SQL types and Java classes.
Notice that in this example, both connection and dbunitConnection were created
using hardcoded values; in real projects, a better practice would be to define these set-
tings externally, such as in a property file. That would allow the same tests to be run in
different environments, such as using alternate databases or getting the connection
from a pooled data source. Getting an IDataSet from an XML file is so common that
it deserves its proper method F . It's also a good practice to load these XML files as
resources in the classpath, instead of physical files in the operating system. And if the
file isn't found in the classpath (which is a common scenario when you're writing the
test cases—you might have forgotten to create the file or misspelled its name), get-
ResourcesAsStream() returns null (instead of throwing a resource-not-found excep-
tion), which in turn would cause a NullPointerException in the caller method.
Because an NPE is a sure bet to cause a lot of headaches, adding an assertNotNull()
G with a meaningful message is a one-liner that can save you time troubleshooting.
Finally, H the DbUnit job is effectively performed. We have a dataset ( setupData-
Set ) with the data we want to insert and a connection to the database ( dbunit-
Connection ). All that's left is the class responsible to do the dirty work, and that's
DatabaseOperation or, more precisely, one of its subclasses. In this case, we use
CLEAN_INSERT , which first deletes all rows from all tables defined in dataset and then
inserts the new ones. See the next section for more details about DatabaseOperation
and its implementations. 6
A final note about transactions: in order to keep this example simple, we aren't
dealing with transactions at all, and every database operation is done in one transac-
tion (using JDBC 's autocommit feature). Although this simplification is fine here, usu-
ally the test cases must be aware of the transaction semantics. For instance, a
transaction could be started before the test (using a @Before method) and committed
afterwards (using @After ), the test cases could explicitly set the autocommit property
(particularly if the connections were obtained from a pool), and so on. The exact
approach depends on many factors, like the type of test (unit or integration) being
written and the underlying technologies used in the code tested (like pure JDBC or
ORM frameworks). 6
6
Chapter 18 offers more detailed insight on transactions in JPA-based test cases.
 
 
Search WWH ::




Custom Search