I am trying to write integration test that uses JUnit, Struts2, Spring, JPA/Hibernate.
The application is working fine in WebSphere. The Integration tests are run outside of WebSphere.
struts2-junit-plugin and spring-struts plugin both are used. My test class extends StrutsSpringTestCase
.
This is the sample code in the test method:
ActionProxy proxy = getActionProxy("custSearch");
assertNotNull(proxy);
It loads struts.xml, applicationContext.xml and jpaContext.xml.
In the jpaContext.xml I have the following entry.
<bean id="dsSQLServer" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndi-name="${sql.jndi.name}"/>
sql.jndi.name
comes from the properties file and is setup in WebSphere.
I went TO properties file and replaced the local jndi url with full jndi url that I got from executing dumpNamespaces.bat of Websphere. which is something like
MycomnameNode01Cell/nodes/C1A-mYNode/servers/mYSrv/jdbc/sql_src
However, when I run the JUnit test case from eclipse I get the following exception.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceSQLServer' defined in URL [file:/C:/workspace/context/jpaContext.xml]: Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Failed to create InitialContext using factory specified in hashtable
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:591)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:148)
at org.apache.struts2.StrutsSpringTestCase.setupBeforeInitDispatcher(StrutsSpringTestCase.java:38)
at org.apache.struts2.StrutsTestCase.setUp(StrutsTestCase.java:187)
at junit.framework.TestCase.runBare(TestCase.java:139)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:129)
at junit.framework.TestSuite.runTest(TestSuite.java:255)
at junit.framework.TestSuite.run(TestSuite.java:250)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:131)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: javax.naming.NoInitialContextException: Failed to create InitialContext using factory specified in hashtable
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:245)
at javax.naming.InitialContext.initializeDefaultInitCtx(InitialContext.java:318)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:348)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:428)
at javax.naming.InitialContext.lookup(InitialContext.java:436)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:87)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:201)
at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 25 more
Questions:
@BeforeClass
method or with Static initializer? Because, the JNDI URL above, Provider URL is missing. The JNDI context is usually provided by your app server (Websphere). As you're running your test from the outside of Websphere, you won't be able to access to a local JNDI. I see 3 solutions...
Ensure that you're connected to the remote JNDI
You should initialize your access properties in a @BeforeClass method :
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, "iiop://server:2809");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
Context ctx = new InitialContext(env);
This way you'll be able to access to the remote JNDI, but a datasource is not supposed to be serialized. It cannot be transfered remotely.
Setup a local JNDI
Spring is providing a SimpleNamingContextBuilder class that can be used in the @BeforeClass method to setup a local JNDI and fill it with a hand made datasource
Don't load the jpaContext.xml file
Make an other one which will provide the dsSQLServer bean, but without accessing the JNDI. A SimpleDriverDataSource would probably be perfect.
My preferred solution is #3.