#Autowired fails with JUnit & Spring - spring

Really need help. I used JUnit(4.6) plus Spring(3.0.5) for unit testing. When I tried to autowire a service object in my test class, I got a NoSuchBeanDefinitionException.
The JUnit code:
package com.aaa.service.impl;
#ContextConfiguration(locations = { "classpath:/spring/applicationContext.xml",
"classpath:/spring/applicationContext-aop.xml",
"classpath:/spring/applicationContext-dao.xml",
"classpath:/spring/applicationContext-service.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class TestManageTargetServiceImpl {
#Autowired
ManageTargetServiceImpl manageTargetServiceImpl;
#Test
public void testQueryFinancialMonthList() {
List<Map<String, Object>> value = new ArrayList<Map<String, Object>>();
ManageTargetDao manageTargetDao = mock(ManageTargetDao.class);
when(manageTargetDao.queryFinancialMonthList()).thenReturn(value);
manageTargetServiceImpl.setManageTargetDao(manageTargetDao);
// I hope it return null
assertNull(manageTargetServiceImpl.queryFinancialMonthList());
}
}
The applicationContext-service.xml code:
<context:annotation-config />
<bean id="manageTargetService" class="com.aaa.service.impl.ManageTargetServiceImpl">
<property name="manageTargetDao" ref="manageTargetDao"></property>
</bean>
The error track:
00:51:28,625 ERROR main context.TestContextManager:324 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#882dfc] to prepare test instance [com.aaa.service.impl.TestManageTargetServiceImpl#ce2db0]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.aaa.service.impl.TestManageTargetServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.aaa.service.impl.ManageTargetServiceImpl com.aaa.service.impl.TestManageTargetServiceImpl.manageTargetServiceImpl; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.aaa.service.impl.ManageTargetServiceImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Some log:
00:51:26,828 DEBUG main context.TestContextManager:282 - beforeTestClass(): class [class com.aaa.service.impl.TestManageTargetServiceImpl]
00:51:26,828 DEBUG main annotation.ProfileValueUtils:68 - Retrieved #ProfileValueSourceConfiguration [null] for test class [com.aaa.service.impl.TestManageTargetServiceImpl]
00:51:26,828 DEBUG main annotation.ProfileValueUtils:80 - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.aaa.service.impl.TestManageTargetServiceImpl]
00:51:26,828 DEBUG main context.TestContextManager:315 - prepareTestInstance(): instance [com.aaa.service.impl.TestManageTargetServiceImpl#ce2db0]
00:51:26,843 DEBUG main support.DependencyInjectionTestExecutionListener:73 - Performing dependency injection for test context [[TestContext#e0eb3f testClass = TestManageTargetServiceImpl, locations = array<String>['classpath:/spring/applicationContext.xml', 'classpath:/spring/applicationContext-aop.xml', 'classpath:/spring/applicationContext-dao.xml', 'classpath:/spring/applicationContext-service.xml'], testInstance = com.aaa.service.impl.TestManageTargetServiceImpl#ce2db0, testMethod = [null], testException = [null]]].
00:51:26,843 DEBUG main support.AbstractGenericContextLoader:75 - Loading ApplicationContext for locations [classpath:/spring/applicationContext.xml,classpath:/spring/applicationContext-aop.xml,classpath:/spring/applicationContext-dao.xml,classpath:/spring/applicationContext-service.xml].
00:51:26,968 INFO main xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [spring/applicationContext.xml]
00:51:27,187 INFO main xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [spring/applicationContext-aop.xml]
00:51:27,312 INFO main xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [spring/applicationContext-dao.xml]
00:51:27,421 INFO main xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [spring/applicationContext-service.xml]
00:51:27,453 INFO main support.GenericApplicationContext:456 - Refreshing org.springframework.context.support.GenericApplicationContext#16c14e7: startup date [Tue Jan 01 00:51:27 NZDT 2013]; root of context hierarchy
00:51:27,718 INFO main config.PropertyPlaceholderConfigurer:177 - Loading properties file from class path resource [jdbc.properties]
00:51:27,796 INFO main support.DefaultListableBeanFactory:555 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#2938d8: defining beans [loggingAop,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,service,loginDao,manageTargetDao,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,dataSource,txManager,txAdvice,txDAO,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,loginService,manageTargetService]; root of factory hierarchy

Guessing here - but given that injection of a class type ManageTargetServiceImpl is failing, I think the reason is that a proxy is getting created for ManageTargetServiceImpl and so the type of the bean will not be ManageTargetServiceImpl anymore but the interface of that class.
from Biju Kunjummen

Look at your property id. It should be manageTargetServiceImpl in your applicationContext-service.xml
Change it to this:
<bean id="manageTargetServiceImpl" class="com.aaa.service.impl.ManageTargetServiceImpl">
<property name="manageTargetDao" ref="manageTargetDao"></property>
</bean>

Related

#WebMvcTest with #Import does not work. Test context always asks for #Repository beans

Using Spring Boot 2.7.3 I can not create a simple integration test for my API using #WebMvcTest.
Here is my setup:
// GameServerApplicationTests.kt
#SpringBootTest
class GameServerApplicationTests {
#Test
fun contextLoads() { }
}
// CraftService.kt
#Service
class CraftService {
fun getAll(): List<String> {
return listOf("foo", "bar")
}
}
// CraftApiTest.kt
#WebMvcTest
#Import(value = [CraftService::class])
class CraftApiTest {
#Autowired
private lateinit var testRestTemplate: TestRestTemplate
#Test
fun `should do accept craft all endpoint`() {
val response = testRestTemplate.getForEntity("/craft/all", String::class.java)
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
}
}
When I run the test I see this exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemRepository' defined in com.gameserver.item.ItemRepository defined in #EnableJpaRepositories declared on GameServerApplication: Cannot create inner bean '(inner bean)#3fba233d' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#3fba233d': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
I have no idea why it is looking for the itemRepository bean at all. I never asked for that.
I then added this
#WebMvcTest
#ComponentScan(excludeFilters = [ComponentScan.Filter(Repository::class)]) // <<
#Import(value = [CraftService::class])
Which resulted in this exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'playerRepository' defined in com.gameserver.player.PlayerRepository defined in #EnableJpaRepositories declared on GameServerApplication: Cannot create inner bean '(inner bean)#30c1da48' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#30c1da48': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
Which confuses me even more. I explictly excluded all #Repository beans - but it just skipped ItemRepository and then asked for PlayerRepository now.
I am totally lost and have no idea why I am not able to setup a simple integration test for my API endpoint.
EDIT #1:
Other tests run just fine:
EDIT #2:
I tried to use a #Configuration bean for #Import.
// CraftApiTestConfiguration
#Configuration
class CraftApiTestConfiguration {
#Bean
fun getCraftService(): CraftService {
return CraftService()
}
}
// CraftApiTest.kt
#WebMvcTest
#Import(CraftApiTestConfiguration::class)
class CraftApiTest { // ... }
That did not help either. It just gave me the second exception mentioned above (the one asking for playerRepository)
I'll try to answer although without seeing the actual code it might not be correct.
So #WebMvcTest loads a "slice" of your application with all the beans annotated with #RestControllers. It doesn't load #Service or #Repository annotated beans.
When you run the test with #WebMvcTest annotation it will load all the controllers, and if, by accident the controller references others than the reference on the service (here I can't say for sure what it is), you might end up loading the stuff that you don't actually need.
Now when you use #WebMvcTest there are two things you can/should do:
Work with MockMvc instead of rest template that queries a web server, its not a full-fledged web layer test anyway.
Try using #WebMvcTest with your controller only:
#WebMvcTest(CraftApisController.class)
Also instead of injecting the real implementation of service, you can use #MockBean so that the real service implementation will be covered by a regular unit test (without spring at all, just plain JUnit/Mockito) and this test could check that your annotations are defined correctly

Reading environment variables or properties in a file

I am trying to deploy a spring-boot 2.0.4 application. The configuration looks like below :
#Component
#Configuration
#PropertySource("classpath:elast.properties")
public class ElastSearchLogLevel {
private static final Logger LOG = LoggerFactory.getLogger(ElastSearchLogLevel.class);
#Value("${elast.mail.to}")
private String to;
...
Locally on windows its working fine but in Linux box it says :
WARN o.a.commons.logging.impl.Jdk14Logger.log - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'elastSearchBootApplication': Unsatisfied dependency expressed through field 'logsSearch'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'elastSearchLogLevel': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'elast.mail.to' in value "${elast.mail.to}"
The instance 'elastSearchLogLevel' is autowired in SpringBootApplication class. Ideally i want to give an external configuration file from which the property can be read. As suggested in one of the forum I also tried but didn't work.
#PropertySource("classpath:file:///my/file/path/elast.properties")
ok some more code :
#ComponentScan(basePackages = "some.packer.log")
#SpringBootApplication
#EnableScheduling
public class ElastSearchBootApplication {
...

Vaadin error "Scope 'vaadin-view' is not active for the current thread"

I'm trying to create Vaadin 7.5.5 app with add-on com.vaadin.vaadin-spring.1.0.0. This is not Spring Boot app, but deploy-able war with Spring context which should bootstrap Vaadin.
The error is:
Scope 'vaadin-view' is not active for the current thread
nested exception is java.lang.IllegalStateException: No active view
Here is full error trace:
2015-09-25 21:27:33 DEBUG DefaultListableBeanFactory:448 - Creating instance of bean 'vaadinSpringApplication'
2015-09-25 21:27:33 DEBUG InjectionMetadata:72 - Registered injected element on class [com.myapp.vaadin.demo.VaadinSpringApplication]: AutowiredFieldElement for com.vaadin.spring.navigator.SpringViewProvider com.myapp.vaadin.demo.VaadinSpringApplication.viewProvider
2015-09-25 21:27:33 DEBUG InjectionMetadata:72 - Registered injected element on class [com.myapp.vaadin.demo.VaadinSpringApplication]: AutowiredFieldElement for com.myapp.vaadin.demo.DefaultView com.myapp.vaadin.demo.VaadinSpringApplication.defaultView
2015-09-25 21:27:33 DEBUG InjectionMetadata:72 - Registered injected element on class [com.myapp.vaadin.demo.VaadinSpringApplication]: AutowiredFieldElement for com.myapp.vaadin.demo.SpringLoginView com.myapp.vaadin.demo.VaadinSpringApplication.springLoginView
2015-09-25 21:27:33 DEBUG InjectionMetadata:72 - Registered injected element on class [com.myapp.vaadin.demo.VaadinSpringApplication]: AutowiredFieldElement for com.myapp.vaadin.demo.SpringMainView com.myapp.vaadin.demo.VaadinSpringApplication.springMainView
2015-09-25 21:27:33 DEBUG InjectionMetadata:86 - Processing injected element of bean 'vaadinSpringApplication': AutowiredFieldElement for com.vaadin.spring.navigator.SpringViewProvider com.myapp.vaadin.demo.VaadinSpringApplication.viewProvider
2015-09-25 21:27:33 DEBUG DefaultListableBeanFactory:250 - Returning cached instance of singleton bean 'viewProvider'
2015-09-25 21:27:33 DEBUG AutowiredAnnotationBeanPostProcessor:490 - Autowiring by type from bean name 'vaadinSpringApplication' to bean named 'viewProvider'
2015-09-25 21:27:33 DEBUG InjectionMetadata:86 - Processing injected element of bean 'vaadinSpringApplication': AutowiredFieldElement for com.myapp.vaadin.demo.DefaultView com.myapp.vaadin.demo.VaadinSpringApplication.defaultView
2015-09-25 21:27:33 DEBUG DefaultListableBeanFactory:448 - Creating instance of bean 'viewCache'
2015-09-25 21:27:33 DEBUG DefaultListableBeanFactory:250 - Returning cached instance of singleton bean 'com.vaadin.spring.VaadinConfiguration'
2015-09-25 21:27:33 DEBUG CommonAnnotationBeanPostProcessor:216 - Found destroy method on class [com.vaadin.spring.internal.DefaultViewCache]: void com.vaadin.spring.internal.DefaultViewCache.destroy()
2015-09-25 21:27:33 DEBUG CommonAnnotationBeanPostProcessor:288 - Registered destroy method on class [com.vaadin.spring.internal.DefaultViewCache]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement#5cd39ffa
2015-09-25 21:27:33 DEBUG DefaultListableBeanFactory:484 - Finished creating instance of bean 'viewCache'
Sep 25, 2015 9:27:33 PM com.vaadin.server.DefaultErrorHandler doDefault
SEVERE:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'vaadinSpringApplication': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.myapp.vaadin.demo.DefaultView com.myapp.vaadin.demo.VaadinSpringApplication.defaultView; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultView': Scope 'vaadin-view' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No active view
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:344)
at com.vaadin.spring.internal.BeanStore.create(BeanStore.java:71)
at com.vaadin.spring.internal.UIScopeImpl$UIBeanStore.create(UIScopeImpl.java:279)
at com.vaadin.spring.internal.BeanStore.get(BeanStore.java:62)
at com.vaadin.spring.internal.SessionLockingBeanStore.get(SessionLockingBeanStore.java:46)
at com.vaadin.spring.internal.UIScopeImpl.get(UIScopeImpl.java:81)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:339)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:219)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1057)
at com.vaadin.spring.server.SpringUIProvider.createInstance(SpringUIProvider.java:172)
at com.vaadin.server.communication.UIInitHandler.getBrowserDetailsUI(UIInitHandler.java:191)
at com.vaadin.server.communication.UIInitHandler.synchronizedHandleRequest(UIInitHandler.java:74)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1408)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:351)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
Here is application main class:
#Theme("valo")
#SpringUI
public class VaadinSpringApplication extends UI {
#Configuration
#EnableVaadin
public static class VaadinSpringApplicationConfiguration {}
#Autowired
SpringViewProvider viewProvider;
#Override
protected void init(VaadinRequest request) {
Navigator navigator = new Navigator(this, this);
navigator.addProvider(viewProvider);
navigator.navigateTo(DefaultView.NAME);
}
}
DefaultView.java
#SpringComponent
#SpringView(name = DefaultView.NAME)
public class DefaultView extends CustomComponent implements View {
public static final String NAME = "defaultView";
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
Button button = new Button("Click Me");
setCompositionRoot(layout);
}
}
As you may see from logs, spring beans (viewCache, defaultView, springLoginView, springMainView) has been created. But once I've tried to inject it into main class - got the error "Scope 'vaadin-view' is not active for the current thread".
Please advice. Thank you.

Instantiation of bean failed : Specified class is an interface

I am facing an issue while creating a bean for dependency injection. Here is the scenario.
I am dealing with MongoDB repository, I have also created a class which uses it. I am trying to instantiate bean instance of both.
MongoDB reporsitory:
#Repository
public interface ProductGlobalTrendRepository extends MongoRepository<ProductGlobalTrend,String>{
public ProductGlobalTrend findByPid(#Param("pId") String pId);
}
The class which is using it:
#Service
#Scope("singleton")
public class ProductTrendService {
#Autowired
#Qualifier("productGlobalTrendRepo")
ProductGlobalTrendRepository productGlobalTrendRepo;
public ProductTrendService() {
super();
}
public void setProductGlobalTrendRepo(
ProductGlobalTrendRepository productGlobalTrendRepo) {
this.productGlobalTrendRepo = productGlobalTrendRepo;
}
public ProductTrendService(ProductGlobalTrendRepository productGlobalTrendRepo) {
super();
this.productGlobalTrendRepo = productGlobalTrendRepo;
}
}
The spring's bean config xml has these entries:
<bean id="productTrendService" class="com.api.services.ProductTrendService"> </bean>
<bean id="productGlobalTrendRepo" class="com.mongodb.repository.ProductGlobalTrendRepository"> </bean>
Following is the error I am getting:
19428 [localhost-startStop-1] WARN
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
- Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'productTrendService': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: com.mongodb.repository.ProductGlobalTrendRepository
com.api.services.ProductTrendService.productGlobalTrendRepo; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'productGlobalTrendRepo' defined in
class path resource [com/vstore/conf/spring-security.xml]:
Instantiation of bean failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [com.mongodb.repository.ProductGlobalTrendRepository]:
Specified class is an interface
It complains that repository is a interface class.
Can somebody please suggest a fix/workaround for this bean dependency injection ?
The problem is with the following information in your context file
<bean id="productGlobalTrendRepo"
class="com.mongodb.repository.ProductGlobalTrendRepository">
</bean>
You should create a class com.mongodb.repository.ProductGlobalTrendRepositoryImpl which implements com.mongodb.repository.ProductGlobalTrendRepository and provides implementation of its methods.
then change your bean declaration info as
<bean id="productGlobalTrendRepo"
class="com.mongodb.repository.ProductGlobalTrendRepositoryImpl">
</bean>
Behind the scene the object is created which is not possible with the interface.

Failed to load ApplicationContext in JUnit with JNDI datasource

I have some troubles testing my application, whereas it works well in normal execution.
I think it comes from JNDI resources which are not found, but I don't understand why and how to fix it.
When I start my Junit test, I got this error:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at ...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DAOImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource com.sample.DAOImpl.myDatasource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDatasource' defined in URL [file:src/test/resources/spring/test-dao-config.xml]: Invocation of init method failed; 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
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
at ...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource com.sample.DAOImpl.myDatasource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
at ...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
at ..
Here is my configuration:
Context.xml
<Resource name="jdbc/myDatasource" auth="Container" type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#database:99999:instance"
username="user"
password="password"
validationQuery="select 1 from dual"
testOnBorrow ="true"
maxActive="5"
maxIdle="1"
maxWait="-1" />
test-dao-config.xml
<bean id="myDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/myDatasource" />
</bean>
DaoImpl
#Repository
public class DacsDAOImpl implements DacsDAO
{
private final static Logger LOGGER = LoggerFactory.getLogger(DAOImpl.class);
#Autowired
#Qualifier("myDatasource")
private DataSource myDatasource;
....
}
And my tests
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/test/resources/spring/test-dao-config.xml" })
public class MyDAOImplTest
{
private MyDAO dao;
#BeforeClass
public static void initJndi() throws IllegalStateException, NamingException
{
//some test, but doesn't work
// SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
// builder.bind("java:comp/env/jdbc/myDatasource", "myDatasource");
// builder.activate();
}
#Before
public void setUp() throws IllegalStateException, NamingException
{
dao = new MyDAOImpl();
}
#Test
public void testTotalUser()
{
int result = dao.getTotalUser();
Assert.assertEquals(0, result);
}
}
Thanks
You are running in a test case so everything in your Context.xml isn't available as that is only available on tomcat. Why do you need a jndi lookup in your test case anyway? If you want to test your dao use an in-memory database like hsql, h2 or derby and use that instead. Spring has some nice tags to make it easy for you.
<jdbc:embedded-database id="myDataSource" type="H2">
// Add some init scripts here.
</jdbc:embedded-database>
If you really need to do a JNDI lookup you are almost there in your test case. However you have to register a DataSource not a String. So you still will need to construct some (in-memory) datasource and bind that to the mock jndi location
#BeforeClass
public static void initJndi() throws IllegalStateException, NamingException
{
//some test, but doesn't work
// Construct in-memory database
SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
builder.bind("java:comp/env/jdbc/myDatasource", myDatasource); //Actual datasource not a String!
builder.activate();
}
And finally your test is also flawed, you are loading your context but aren't doing anything with it. You are constructing a MyDAOImpl in your #Before method. Why even bother loading the context as you are doing nothing with.

Resources