单元测试困境:在不运行JBoss或Spring的情况下使用JNDI数据源

Lau*_*ura 16 java eclipse junit unit-testing jndi

问题陈述

我希望能够对连接到数据库的方法运行junit测试.

当前设置

Eclipse Java EE IDE - Java代码不使用框架.开发人员(包括我)希望在尝试将代码移动到Spring框架之前对当前遗留代码进行更强大的测试,以便我们可以证明行为仍然是正确的.

JBoss 4.2 - 供应商软件的版本限制(Adobe LiveCycle ES2); 我们的Java Web应用程序使用这种JBoss设置来运行和使用Adobe LiveCycle API.

我们无法在Eclipse中成功运行供应商配置的JBoss - 我们花了数周时间尝试这一点,包括联系提供我们支持JBoss for Adob​​e LiveCycle配置的公司.据说问题是Eclipse中的设置存在内存限制问题,但是在Eclipse中成功启动JBoss服务器之前,更改内存设置已经失败了.目前,试图让JBoss在Eclipse内运行是暂时搁置的.

数据库连接在JBoss在启动时加载的JNDI数据源中定义.我们的Web应用程序和Adobe LiveCycle都需要创建与此数据源的连接.

我正在浏览此代码片段中的错误检查和类结构,以关注问题的核心.希望这不会给别人带来麻烦.方括号中的文本不是实际文本.

我们创建连接的代码是这样的:

Properties props = new Properties();
FileInputStream in = null;
in = new FileInputStream(System.getProperty("[Properties File Alias]"));
props.load(in);
String dsName = props.getProperty(“[JNDI data source name here]”); 
InitialContext jndiCntx = new InitialContext();
DataSource ds = (DataSource) jndiCntx.lookup(dsName);
Ds.getConnection();
Run Code Online (Sandbox Code Playgroud)

我希望能够测试依赖于此代码的方法,而无需对其进行任何更改.

在properties-service.xml文件中引用属性文件别名:

  <!-- ==================================================================== -->
  <!-- System Properties Service                                            -->
  <!-- ==================================================================== -->

  <!-- Allows rich access to system properties.-->

<mbean code="org.jboss.varia.property.SystemPropertiesService" 
 name="jboss:type=Service,name=SystemProperties">
  <attribute name="Properties">
    [Folder Alias]=[filepath1]
    [Properties File Alias]=[filepath2]
  </attribute>
</mbean>
Run Code Online (Sandbox Code Playgroud)

位于filepath2的属性文件的片段

[JNDI data source name]=java:/[JNDI data source name]
Run Code Online (Sandbox Code Playgroud)

此数据源的JNDI xml文件设置如下:

<datasources>
  <local-tx-datasource>
    <jndi-name>[JNDI data source name here]</jndi-name>
    <connection-url>jdbc:teradata://[url]/database=[database name]</connection-url>
    <driver-class>com.teradata.jdbc.TeraDriver</driver-class>
    <user-name>[user name]</user-name>
    <password>[password]</password>
    <!-- sql to call on an existing pooled connection when it is obtained from pool -->
    <check-valid-connection-sql>SELECT 1+1</check-valid-connection-sql>
  </local-tx-datasource>
</datasources>
Run Code Online (Sandbox Code Playgroud)

我对解决方案可能在哪里的想法

有没有我可以在@BeforeClass方法中做的事情,以便使上面的代码在没有JBoss的情况下寻找可用的属性?也许以某种方式使用java.util.Properties类的setProperty方法?如果可能的话,我还想使用JBoss读取的相同JNDI xml文件,以减少重复的配置设置.

到目前为止,我的所有研究都以"使用春天"的建议结束,但我认为我们还没准备好打开那种蠕虫病毒.我不是JBoss的专家,但是如果需要更多关于JBoss设置的详细信息以获得有用的答案,我将尽我所能得到它们,尽管我可能需要一些关于在哪里寻找的指针.

计算器研究参考:
使用JUnit的春天JNDI查找
走出容器JNDI数据源的
其他研究提供参考:
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Properties.html
HTTP:/ /docs.oracle.com/javase/jndi/tutorial/basics/prepare/initial.html

wel*_*rat 7

对你的问题有一个非常简单的答案,但你不会喜欢它:不要.

根据定义,单元测试应该验证单个单元的功能(其大小可以变化,但它应该是自给自足的).创建一种设定,测试依赖于Web服务,数据库等是适得其反:它减慢您的测试,包括可能的事情可能出错一个gzillion(失败的网络连接,更改数据集,... )在测试期间,这与您正在处理的实际代码无关,最重要的是:它使测试变得更加困难,更加复杂.

相反,您应该寻找遗留代码与任何数据源分离的方法,以便在测试时可以轻松替换模拟对象或类似的测试双精度.

应该创建测试来验证整个堆栈的完整性,但这些测试称为集成测试,并且它们在更高的抽象级别上运行.我个人喜欢推迟写这些,直到单位本身到位,测试和工作 - 至少在你不再期望每天改变服务电话和协议之前.

在您的情况下,最明显的策略是在一个或多个单独的类中封装对Web服务的所有调用,提取业务对象可以依赖的接口,并使用实现相同接口的模拟进行单元测试.

例如,如果您有一个调用地址数据库的业务对象,则应将JNDI查找代码复制到一个名为的新服务类中AddressServiceImpl.它的公共方法应该模仿JNDI数据源的所有方法签名.那些,然后,你提取到AddressService界面.

然后,您可以编写一个简单的集成测试来验证新类是否有效:调用所有方法一次,看看是否得到了正确的结果.这样做的好处是,您可以提供指向测试数据库(而不是原始数据库)的JNDI配置,您可以使用测试数据集填充该数据集以确保始终获得预期结果.你不一定需要一个JBoss实例(尽管我从来没有遇到过eclipse集成的任何问题) - 只要数据源本身的行为方式相同,任何其他JNDI提供者都应该工作.并且要明确:你测试一次,然后忘掉它.至少在实际服务方法发生变化之前.

一旦确认服务正常运行,下一个任务就是遍历所有依赖类,并通过调用AddressService接口替换对数据源的直接调用.从那时起,您有一个适当的设置来实现对实际业务方法的单元测试,而不必担心应该在别处测试的事情;)

编辑

我是对Mockito的推荐.真的很好!