在利用Spring和iBatis做一个应用时,用到了数据库连接池。在Spring配置文件中,jndi配置如下
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>jdbc/mysql</value></property>
<property name="lookupOnStartup" value="false"/>
<property name="cache" value="false"/>
<property name="resourceRef" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
但是在junit进行单元测试时,出现了问题。
org.springframework.jndi.JndiLookupFailureException: JndiObjectTargetSource failed to obtain new target object; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.lookup(Unknown Source)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:123)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:85)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:121)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:146)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:93)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at org.springframework.jndi.JndiObjectTargetSource.getTarget(JndiObjectTargetSource.java:126)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:184)
at $Proxy0.getConnection(Unknown Source)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:200)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:350)
at org.springframework.test.AbstractTransactionalSpringContextTests.startNewTransaction(AbstractTransactionalSpringContextTests.java:387)
at org.springframework.test.AbstractTransactionalSpringContextTests.onSetUp(AbstractTransactionalSpringContextTests.java:217)
at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:103)
at junit.framework.TestCase.runBare(TestCase.java:128)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
在junit环境下连接数据源失败,为什么呢,因为jndi是在tomcat下配置的,但是用junit进行单元测试的环境下是独立于tomcat的,不能够与jndi中的数据相连。这种问题有两种解决办法。
一是在进行单元测试时,利用jdbc连接数据库。将Spring配置文件中的dataSource部分改成下面的方式:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/cms</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>admin</value>
</property>
</bean>
二是利用Spring针对单元测试而扩展的功能:
个人认为第一种方法比较方便,只需要在进行单元测试时利用jdbc的方式,在控制层测试时,可以将其再转换到jndi的方式上去。第二种方法通过扩展Spring的功能,相当于在java代码中重新创建了一个dataSource,而不是通过配置文件。