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

Java 在J2ee应用程序上为DAO编写测试用例,java,jakarta-ee,junit,Java,Jakarta Ee,Junit,我试图在J2EE应用程序中为我的DAO类编写一些测试用例。我的DAO类中的方法尝试基于JDBCURL(在应用服务器上)连接到数据库。因此,从前端开始,如果我点击一堆东西并使DAO触发,它运行良好。但是,当我为DAO编写测试用例,并且DAO对象调用该方法时,它无法获得到数据库的连接。我认为,由于JDBC资源位于应用服务器上,因此它不能从测试类工作 因此,当我运行测试而不是通过或失败时,它会返回大量错误 有人遇到过这个问题吗?我能做些什么来克服这个问题 例如: public class DBConn

我试图在J2EE应用程序中为我的DAO类编写一些测试用例。我的DAO类中的方法尝试基于JDBCURL(在应用服务器上)连接到数据库。因此,从前端开始,如果我点击一堆东西并使DAO触发,它运行良好。但是,当我为DAO编写测试用例,并且DAO对象调用该方法时,它无法获得到数据库的连接。我认为,由于JDBC资源位于应用服务器上,因此它不能从测试类工作

因此,当我运行测试而不是通过或失败时,它会返回大量错误

有人遇到过这个问题吗?我能做些什么来克服这个问题

例如:

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)

这可能是您试图访问的数据库的权限问题。你犯了什么错误

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


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

首先测试好ServiceLocator。正如您所提到的,问题可能是因为数据源是在服务器上声明的。这里的“一堆错误”应该是有帮助的,比如问题是在获取数据源还是连接本身。
你在使用什么数据库?您可以从控制台从计算机登录到它吗?如果没有,请对其进行配置,以便允许您的主机。

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;                
    }
}
您没有显示有关正确关闭资源或事务的任何信息。根据这个密码判断,你在这两方面都会有麻烦。我会仔细考虑你的实施

我将向您推荐SpringJDBC。您可以在春季编写DAO,而无需重写整个应用程序


我还将指出,您可能也在研究泛型:.

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

实际上,我编写这个测试用例的目的不仅仅是测试数据访问。一周前我问了这个问题。这也许能告诉你我真正想做什么。此外,我收到的错误类似于“../logs/myapp.log”,系统无法找到指定的路径。所有这些错误都是因为我不是直接来自web层。有没有一种方法可以“模拟”测试这样的方式让他们看起来像是来自web层…看起来像是安全问题。NoClassDefFoundError:com/iplanet/ias/admin/common/asException谢谢,我喜欢将连接传递给DAO的设计。但是,假设您有一个实际调用DAO的DAO助手类……该助手类会传递到DAO的连接吗?我不认为现在我可以改变设计……我想我将不得不放弃可怕的测试想法>\u你能建议一种方法,让我的DAO中的getContents()方法知道它是否是从JUnit方法调用的吗。如果是…那么它将从驱动程序管理器获取连接…不,您的DAO不应该知道它是否正在测试或在应用程序中使用。从其他地方传入连接。根据您提供的代码…MyDAO类中的连接变量永远不会被填充(除非我读错了?)。假设我启动MyDAO myd=newmydao();那么在哪里调用getConnection(在DBConnectionManager中)?是的,您读错了。没有默认构造函数,只有一个将传入的连接作为参数的构造函数。如果没有我编写的连接,就无法创建DAO。这就是Java的工作方式——如果不编写构造函数,您只能从编译器获得一个默认构造函数。模拟连接有什么意义?如果您正在测试DAO,为什么不想连接到真正的数据库?这是对mock的一种使用,从来没有做过