在J2ee应用程序上为DAO编写测试用例

时间:2009-11-08 22:53:29

标签: java java-ee junit

我正在尝试为J2EE应用程序中的DAO类编写一些测试用例。我的DAO类中的方法尝试基于JDBC URL(位于应用服务器上)与数据库建立连接。所以从前端如果我点击一堆东西并使DAO触发它运行正常。但是,当我为DAO编写测试用例并且DAO对象调用该方法时,它无法获得与数据库的连接。我认为,因为JDBC资源在App服务器上,这就是为什么它不能从测试类中运行。

因为这个,当我运行我的测试而不是传递或失败时..返回一堆错误。

有人遇到过这个问题吗?我该怎么做才能克服这个问题?

示例:

public class DBConnectionManager {
   public static final String DB_URL = "jdbc/RSRC/my/connection/mydb"
   public Connection getconnection ()
   {
     DataSource ds = ServiceLocator.getInstance().getDataSource(DB_URL);
     return ds.getconnection();
   } 
}
public class MyDAO extends DBConnectionManager {
    publci SomeBean getContents (String id)
    {
        Connection con = getConnection();
        CallableStatement cs = con.prepareCall("{call myStorProc(?)}");
        cs.setString(1, id);
        ...
        //code to call resultset and retrieve SomeBean goes here
        ..
        return SomeBean;                
    }
}
public class MyTests extends TestCase {
    public testGetcontents ()
    {
        MyDAO myd = new MyDAO ();
        SomeBean smb = myd.getContents("someparm");
        assertEquals (5, smb.getSomeVal());
    }
}

我应该在我的测试用例中做些额外的事情......?如果是这样的话?

编辑:

我得到的错误是:

java.lang.NoClassDefFoundError: com/iplanet/ias/admin/common/ASException
        at java.lang.ClassLoader.defineClass1(Native Method)

4 个答案:

答案 0 :(得分:2)

你的DAO有一个硬连线的JNDI查找字符串。除非您有可用的JNDI查找服务,否则它将无法建立连接。

我认为DAO不应该负责获取数据库连接。此设计不允许您为工作单元设置事务,因为DAO无法知道它是否是更大工作单元的一部分。

我建议将连接传递给DAO,也许是将其传递给它的构造函数。这样,如果单个工作单元中有多个DAO,则服务层可以建立适当的事务边界。

此设计的另一个好处是,您的应用程序可以正确使用其JNDI资源,并通过测试从DriverManager获取其连接,而无需使用JNDI查找。您有两个不同的来源来获取数据源或连接 - 一个用于应用程序,另一个用于测试。

更新:

这就是我的意思,用你的代码表达:

public class DBConnectionManager 
{
    public static final String DB_URL = "jdbc/RSRC/my/connection/mydb"

    public Connection getConnection (String jndiLookup)
    {
        DataSource ds = ServiceLocator.getInstance().getDataSource(jndiLookup);

        return ds.getconnection();
    } 

    public Connection getConnection(String driver, String url, String username, String password)
        throws ClassNotFoundException, SQLException
    {
        Class.forName(driver);

        return DriverManager.getConnection(url, username, password);
    }
}

public class MyDAO 
{
    private Connection connection;

    public MyDao(Connection connection)
    {
        this.connection = connection;
    }

    public SomeBean getContents (String id)
    {
        CallableStatement cs = this.connection.prepareCall("{call myStorProc(?)}");
        this.connection.setString(1, id);

        //code to call resultset and retrieve SomeBean goes here

        return someBean;                
    }
}

您没有显示正确关闭资源或交易。从这个代码判断,你将在两个方面遇到麻烦。我会仔细考虑你的实施。

我会向你推荐Spring JDBC。您可以在Spring中编写DAO,而无需重写整个应用程序。

我还要指出,您可能也在查看泛型:Don't Repeat The DAO

答案 1 :(得分:1)

首先测试你的ServiceLocator。如您所述,问题可能是因为数据源是在服务器上声明的。在这里,“一堆错误”应该是有用的,无论问题是在获取DataSource还是Connectiion本身。 你用的是什么数据库?你可以从你的机器从控制台登录吗?如果不是 - 配置它以便允许您的主机。

答案 2 :(得分:0)

这可能是您尝试访问的数据库的权限问题。你得到了什么错误?

测试数据库访问的一种有用方法是在测试工具中创建数据库的干净,本地“测试”版本。在运行测试之前,使用脚本创建包含所有相关数据的数据库的本地副本,然后针对该数据而不是远程服务器运行测试。

人们可能会争辩说,在单元测试中对数据库进行测试并不是真正的单元测试,因为它具有外部依赖性。如果您能够重构DAO类,则可以通过某些接口注入实际数据源。在您的测试代码中,您将注入一个“模拟”数据源,以一些内存格式提供您的测试数据,然后在生产中,您将使用/注入实际的数据库源类。如果您可以隐藏DAO后面的外部(非业务代码相关)部分,则可以在单元测试中使用模拟来测试更多功能,而不是实际的数据访问。

答案 3 :(得分:0)

我工作的地方我们的DAO有一个可注入的连接(通过构造函数注入),我们对模拟连接进行单元测试。为了测试DAO中的代码,我们传入一个模拟的(通常使用Mockito)连接,并在单元测试中设置关于将调用哪些方法的期望。这使得有些嘈杂的测试,因为测试看起来非常类似于正在开发的代码,但它适用于我们。