- 数据库集成单元测试--------这类测试主要是检测数据库的功能:连接,查询,存储过程,触发,约束以及引用完整性.这些测试必须在容器内并且有数据 源相连的情况下进行.有很多第三方工具可以用来做这种测试,比如用cactus来进行容器内测试,DbUnit来预载测试数据库. 为了运行集成单元测试,我们的测试框架需要有两个功能:将测试数据预置进数据库的能力和从运行的容器内进行测试的能力. 我们的测试策略是用JBoss做为J2EE容器.MySQL作为测试数据库.Cactus作为测试代理.DbUnit作为装载及比较数据的工具,Ant作为运行测试工具.下面让我们进入测试吧.
编写真正的JdbcDataAccessManager类:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.commons.beanutils.RowSetDynaClass;
public class JdbcDataAccessManager implements DataAccessManager
{
private DataSource dataSource;
public JdbcDataAccessManager() throws NamingException
{
this.dataSource = getDataSource();
}
protected DataSource getDataSource() throws NamingException
{
InitialContext context = new InitialContext();
DataSource dataSource =
(DataSource) context.lookup("java:/MySqlDS");
return dataSource;
}
protected Connection getConnection() throws SQLException
{
return this.dataSource.getConnection();
}
public Collection execute(String sql) throws Exception
{
Connection connection = getConnection();
// For simplicity, we'll assume the SQL is a SELECT query
ResultSet resultSet =
connection.createStatement().executeQuery(sql);
RowSetDynaClass rsdc = new RowSetDynaClass(resultSet);
resultSet.close();
connection.close();
return rsdc.getRows();
}
}
注意要配置一个mysql数据源.假设在mysql数据库里建了一个叫jbossdb的数据库.然后在%JBOSS_HOME%/docs/examples/jca目录下找到mysql-ds.xml文件,对它进行编辑.
<?xml version="1.0" encoding="UTF-8"?>
<!-- ===================================================================== -->
<!-- -->
<!-- JBoss Server Configuration -->
<!-- -->
<!-- ===================================================================== -->
<!-- $Id: mysql-ds.xml,v 1.1 2002/07/22 22:57:24 d_jencks Exp $ -->
<!-- ==================================================================== -->
<!-- Datasource config for MySQL using 2.0.11 driver -->
<!-- ==================================================================== -->
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/jbossdb</connection-url>
<driver-class>org.gjt.mm.mysql.Driver</driver-class>
<user-name>sa</user-name>
<password></password>
</local-tx-datasource>
</datasources>
保存以后考到%JBOSS_HOME%/server/default/deploy目录下(假设你的JBOSS服务器以default模式起).下面编写测试代码:
import java.util.Collection;
import java.util.Iterator;
import javax.naming.InitialContext;
import org.apache.cactus.ServletTestCase;
import org.apache.commons.beanutils.DynaBean;
import org.dbunit.database.DatabaseDataSourceConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.operation.DatabaseOperation;
public class TestJdbcDataAccessManagerIC extends ServletTestCase
{
protected void setUp() throws Exception
{
IDatabaseConnection connection =
new DatabaseDataSourceConnection(new InitialContext(),
"java:/MySqlDS");
IDataSet dataSet = new FlatXmlDataSet(
this.getClass().getResource(
"/junitbook/database/data.xml"));
try
{
DatabaseOperation.CLEAN_INSERT.execute(connection,
dataSet);
}
finally
{
connection.close();
}
}
public void testExecuteOk() throws Exception
{
JdbcDataAccessManager manager =
new JdbcDataAccessManager();
Collection result =
manager.execute("SELECT * FROM CUSTOMER");
Iterator beans = result.iterator();
assertTrue(beans.hasNext());
DynaBean bean1 = (DynaBean) beans.next();
assertEquals("John", bean1.get("firstname"));
assertEquals("Doe", bean1.get("lastname"));
assertTrue(!beans.hasNext());
}
}
在setup()里我们利用DbUnit从一个xml文件转载测试数据到数据库里.这里需要一个xml文件data.xml
<dataset>
<CUSTOMER FIRSTNAME="John" LASTNAME="Doe"/>
</dataset>
可以把它和测试代码文件放在同一个目录下.这个TestCase就是先在数据库里的Customer表里加一条记录,再进行测试.table我们可以利用ant来建,先编写一个data.sql
CREATE TABLE CUSTOMER (lastname varchar primary key,
firstname varchar);
. 注意所有文件以及需要的包的安放按照junit test的传统安置方式安放.好,要用ant来运行了,先写build.xml
build.properties
cactus.home.jboss3x = E:/JBoss/jboss-3.2.3/jboss-3.2.3
database = //localhost:3306/jbossdb
lib.dir = ../repository
mysqldb.jar = ${cactus.home.jboss3x}/server/default/lib/mm.mysql-2.0.4-bin.jar
beanutils.jar = ${lib.dir}/commons-beanutils/jars/commons-beanutils-1.6.1.jar
collections.jar = ${lib.dir}/commons-collections/jars/commons-collections-2.1.jar
servlet.jar = ${lib.dir}/servletapi/jars/servletapi-2.3.jar
cactus.jar = ${lib.dir}/cactus/jars/cactus-1.6.1.jar
cactus.ant.jar = ${lib.dir}/cactus/jars/cactus-ant-1.6.1.jar
aspectjrt.jar = ${lib.dir}/aspectj/jars/aspectjrt-1.1.1.jar
dbunit.jar = ${lib.dir}/dbunit/jars/dbunit-1.5.5.jar
exml.jar = ${lib.dir}/dbunit/jars/exml-dbunit-1.5.5.jar
logging.jar = ${lib.dir}/commons-logging/jars/commons-logging-1.0.3.jar
httpclient.jar = ${lib.dir}/commons-httpclient/jars/commons-httpclient-2.0-rc1.jar
build.xml
<?xml version="1.0"?>
<project name="Database" default="test" basedir=".">
<property file="build.properties.sample"/>
<property name="conf.dir" location="conf"/>
<target name="compile">
<mkdir dir="target/classes"/>
<javac destdir="target/classes" srcdir="src/java">
<classpath>
<pathelement location="${beanutils.jar}"/>
<pathelement location="${servlet.jar}"/>
</classpath>
</javac>
</target>
<target name="war" depends="compile">
<war destfile="target/database.war"
webxml="src/webapp/WEB-INF/web.xml">
<classes dir="target/classes"/>
<lib file="${beanutils.jar}"/>
<lib file="${collections.jar}"/>
</war>
</target>
<target name="createdb" depends="war">
<sql driver="org.gjt.mm.mysql.Driver"
url="jdbc:mysql{database}"
userid="root"
password="">
<fileset dir="${conf.dir}">
<include name="data.sql" />
</fileset>
<classpath>
<pathelement location="${mysqldb.jar}"/>
</classpath>
</sql>
</target>
<target name="clean">
<delete dir="target"/>
</target>
<!-- Targets related to Cactus testing -->
<target name="compile.cactustest" depends="createdb">
<mkdir dir="target/cactus-test-classes"/>
<javac destdir="target/cactus-test-classes"
srcdir="src/test-cactus">
<classpath>
<pathelement location="target/classes"/>
<pathelement location="${beanutils.jar}"/>
<pathelement location="${dbunit.jar}"/>
<pathelement location="${cactus.jar}"/>
</classpath>
</javac>
<copy todir="target/cactus-test-classes">
<fileset dir="src/test-cactus">
<include name="**/*.xml"/>
</fileset>
</copy>
</target>
<target name="test" depends="war,compile.cactustest">
<taskdef resource="cactus.tasks">
<classpath>
<pathelement location="${cactus.ant.jar}"/>
<pathelement location="${cactus.jar}"/>
<pathelement location="${logging.jar}"/>
<pathelement location="${aspectjrt.jar}"/>
<pathelement location="${httpclient.jar}"/>
</classpath>
</taskdef>
<cactifywar srcfile="target/database.war"
destfile="target/test.war">
<classes dir="target/cactus-test-classes"/>
<lib file="${dbunit.jar}"/>
<lib file="${exml.jar}"/>
</cactifywar>
<cactus warfile="target/test.war" fork="yes" printsummary="yes"
haltοnerrοr="true" haltonfailure="true">
<containerset>
<jboss3x dir="${cactus.home.jboss3x}"
output="target/jbossresult.txt">
</jboss3x>
</containerset>
<formatter type="brief" usefile="false"/>
<batchtest>
<fileset dir="src/test-cactus">
<include name="**/TestJdbcDataAccessManagerIC.java"/>
</fileset>
</batchtest>
<classpath>
<pathelement location="target/classes"/>
<pathelement location="target/cactus-test-classes"/>
<pathelement location="${dbunit.jar}"/>
</classpath>
</cactus>
</target>
</project>
接着我们就可以run case了,我试了一下没问题,若有问题,应该是配置或版本出了问题.
我本人对JUnit进行数据库测试的看法是,在测试之前一定要有一个好的测试策略,在这基础之上在进行测试代码的编写.对数据库业务逻辑和数据库访问代码 的测试代码编写相对简单一些.对数据库进行集成测试要复杂和麻烦一些,但在这过程中能学到不少东西和加深对一些过程和配置的理解.
以上是我一些不成熟的学习心得,在这抛砖引玉,希望更多的同行来讨论.