JUnit关于数据库访问的单元测试 (2)

  • 对数据库访问的单元测试--------数据库访问代码用一套持久化API访问你的数据库.这类测试的目标是验证你是否正确使用了持久化API.测试策略主要是采用mock objects来模拟持久化API在不与数据库连接并且不在容器内的情况下运行测试. 现在我们来测试数据库访问代码.JDBC,JDO等等本身设计得很好,并且使用java接口,这样一来就非常适宜于mock objects策略.对于 JDBC API 来说,有现成的mock objects包(MockObjects.com JDBC API),它比较成熟,已经为JDBC代码单 元测试作好了准备.下面是我们要测的数据库访问代码:

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();
    }

          // depending on application server
    protected DataSource getDataSource() throws NamingException
    {
        InitialContext context = new InitialContext();
        DataSource dataSource = 
            (DataSource) context.lookup("java:/DefaultDS");
        return dataSource;
    }
   
    /* create a javax.sql.DataSource on BEA Weblogic
  • at first you need to use the Weblogic console http://localhost:7001/console to configure a new connection pool, and a new DataSource associated with this pool
see        http://books.google.de/books?id=Q73uNcj1yv8C&pg=PA481&lpg=PA481&dq=java:/comp+weblogic&source=web&ots=pv9YpIfNp1&sig=3lwyM1yQMIUMSq4ZedkmlZ3Of34&hl=en#PPA482,M1
http://edocs.bea.com/wls/docs81/jndi/jndi.html
http://dev2dev.bea.com/pub/a/2004/01/142.html
  
    protected DataSource getDataSource() throws NamingException
    {    

	Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL,
"t3://localhost:7001");

Context context = new InitialContext(ht);
return getConnection(context, "definedDataSourceName");
    }

   
protected Connection getConnection(Context context, String datasource) throws SQLException
    {
       return (javax.sql.DataSource) context.lookup(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();
    }
}

      数据库访问代码主要在execute方法内,我们要给里面的使用到的JDBC API提供mock objects,首先我们需要模拟 Connection对象,接着模拟的Connection对象就可以返回mock ResultSet,mock Statement等等.现在我们关 心的问题是如何将一个mock Connection对象传递给JdbcDataAccessManager类.很简单,再写一个 JdbcDataAccessManager的子类,添加setter方法,我们测了这个子类也就相当于测了DataAccessManager类.

import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.NamingException;
import javax.sql.DataSource;

public class TestableJdbcDataAccessManager 
    extends JdbcDataAccessManager
{
    private Connection connection;

    public TestableJdbcDataAccessManager() throws NamingException
    {
        super();
    }

    public void setConnection(Connection connection)
    {
        this.connection = connection;
    }

    protected Connection getConnection() throws SQLException
    {
        return this.connection;
    }

    protected DataSource getDataSource() throws NamingException
    {
        return null;
    }
}


      下面我们来编写测试代码:

import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;

import org.apache.commons.beanutils.DynaBean;

import com.mockobjects.sql.MockConnection2;
import com.mockobjects.sql.MockResultSetMetaData;
import com.mockobjects.sql.MockSingleRowResultSet;
import com.mockobjects.sql.MockStatement;

import junit.framework.TestCase;

public class TestJdbcDataAccessManagerMO4 extends TestCase
{
    private MockSingleRowResultSet resultSet;
    private MockResultSetMetaData resultSetMetaData;    
    private MockStatement statement;
    private MockConnection2 connection;
    private TestableJdbcDataAccessManager manager;

    protected void setUp() throws Exception
    {
        resultSetMetaData = new MockResultSetMetaData();

        resultSet = new MockSingleRowResultSet();
        resultSet.setupMetaData(resultSetMetaData);

        statement = new MockStatement();

        connection = new MockConnection2();
        connection.setupStatement(statement);

        manager = new TestableJdbcDataAccessManager();
        manager.setConnection(connection);
    }

    protected void tearDown()
    {
        connection.verify();
        statement.verify();
        resultSet.verify();
    }
        
    public void testExecuteOk() throws Exception
    {
        String sql = "SELECT * FROM CUSTOMER";
        statement.addExpectedExecuteQuery(sql, resultSet);        

        String[] columnsUppercase = new String[] {"FIRSTNAME", 
            "LASTNAME"}; 
        String[] columnsLowercase = new String[] {"firstname", 
            "lastname"};
        String[] columnClasseNames = new String[] {
            String.class.getName(), String.class.getName()};
        
        resultSetMetaData.setupAddColumnNames(columnsUppercase);
        resultSetMetaData.setupAddColumnClassNames(
            columnClasseNames);
        resultSetMetaData.setupGetColumnCount(2);
        
        resultSet.addExpectedNamedValues(columnsLowercase,
            new Object[] {"John", "Doe"});

        connection.setExpectedCreateStatementCalls(1);
        connection.setExpectedCloseCalls(1);
               
        Collection result = manager.execute(sql);
        
        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());
    }

    public void testExecuteCloseConnectionOnException() 
        throws Exception
    {
        String sql = "SELECT * FROM CUSTOMER";

        statement.setupThrowExceptionOnExecute(
            new SQLException("sql error"));

        connection.setExpectedCloseCalls(1);
        
        try
        {
            manager.execute(sql);
            fail("Should have thrown a SQLException");
        }
        catch (SQLException expected)
        {
            assertEquals("sql error", expected.getMessage());
        }                   
    }
}

      首先,我们用mockobject.sql包里的MockConnection建立一个 Mock Connection对象, TestableJdbcDataAccessManager把它设置进去,然后再设置Mock Statement和Mock ResultSet,并 且设置Mock ResultSet返回的期望值.然后我们就可以来进行单元测试了, 去验证数据库访问代码的返回值.注意:在tearDown()里的 connection,statement和resultSet的verify方法.这是对模拟对象添加的预期验证.比如 statement.addExpectedExecuteQuery(sql, resultSet) statement.verify()就会验证 SQL字符串是不是就是不做任何修改地传递过来的那个,执行结果是不是resultSet对象. connection.setExpectedCreateStatementCalls(1) connection.verify就会验证是否仅创建 了一个Statement.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值