Announcement Announcement Module
Collapse
No announcement yet.
Autowire fails in Unit Test Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Autowire fails in Unit Test

    I am attempting to create a sample unit test without much success. If I had any hair, I would be pulling it out by now.

    I have an existing class named QuickBooksAccountDao (which implements an interface IQuickBooksAccountDao) for which I am trying to write a simple test. However, I cannot seem to get past the issue that Spring cannot find the class to inject into the test class. I have been working on this more hours than I care to admit and realize that I must be overlooking something entirely obvious to someone else. Does anyone have any suggestions??

    TestAccounts4.java
    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:**/metalsmith-service-test.xml","classpath:**/metalsmith-test-data.xml"})
    public final class TestAccounts4 {
    	private QuickBooksAccountDao qbAccountDao;
    	@Autowired
    	public void setQbAccountDao(QuickBooksAccountDao qbAccountDao) {
    		this.qbAccountDao = qbAccountDao;
    	}
    
    	@Test
    	public void testGetQuickBooksAccount() {
    		List<QuickBooksAccount> accounts = qbAccountDao.getAllAccounts(1);
    		Assert.assertNotNull(accounts);
    	}
    }
    metalsmith-service-test.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="http://www.springframework.org/schema/context" 
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans.xsd
    	http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    	<context:component />
    	<!--  Spring Beans -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<property name="dataSource"><ref bean="dataSource" /></property>
    	</bean>
    	<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
    		<constructor-arg><ref bean="dataSource"/></constructor-arg>
    	</bean>
      	<bean id="qbAccountDao" class="com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao" >
    		<property name="jdbcTemplate"><ref bean="jdbcTemplate" /></property>
    		<property name="simpleJdbcTemplate"><ref bean="simpleJdbcTemplate" /></property>
    	</bean>		
    </beans>
    JUnit failure trace
    Code:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.othenos.metalsmith.test.TestAccounts4': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.othenos.metalsmith.test.TestAccounts4.setQbAccountDao(com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao] is defined: Unsatisfied dependency of type [class com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao]: expected at least 1 matching bean
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:256)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:998)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:329)
    	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
    	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:255)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:111)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:148)
    	at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    	at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    	at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    	at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    	at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
    	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)
    Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.othenos.metalsmith.test.TestAccounts4.setQbAccountDao(com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao] is defined: Unsatisfied dependency of type [class com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao]: expected at least 1 matching bean
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:543)
    	at org.springframework.beans.factory.annotation.InjectionMetadata.injectMethods(InjectionMetadata.java:117)
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:253)
    	... 19 more
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao] is defined: Unsatisfied dependency of type [class com.othenos.metalsmith.dbaccess.quickbooks.QuickBooksAccountDao]: expected at least 1 matching bean
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:613)
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:499)
    	... 21 more

  • #2
    Is that the entire JUnit stacktrace? Is there any additional information in the console?

    Regarding component scanning, you should use something like:

    Code:
    <context:component-scan base-package="org.example"/>
    instead of what you have above, i.e.:

    Code:
    <context:component />
    You'll find further details here in the reference manual: http://static.springsource.org/sprin...spath-scanning

    Regards,

    Sam

    Comment


    • #3
      Sam, thanks for the comments and suggestion.

      Yes, that was the entire JUnit stacktrace. The console just had these warnings.

      log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUn it4ClassRunner).
      log4j:WARN Please initialize the log4j system properly.
      What I found was that I needed to add the @Component tag to the bean class QuickBooksAccountDao and it would load. However, the dependencies (jdbcTemplate and simpleJdbcTemplate) are still not getting instantiated with the QuickBooksAccountDao bean. Can you suggest what needs to be done to get them to created too?

      By the way, <context:component/>, <context:annotation-config/> or <context:component-scan base-package="com.othenos.metalsmith.dbaccess.quickbook s" /> will all load the QuickBooksAccountDao bean now that it is annotated with @Component.

      Comment


      • #4
        I found the problem. I needed to use the @Autowired notation in the QuickBooksAccountDao for the jdbcTemplate and simpleJdbcTemplate fields.

        BTW, I removed all references to <context:... in the configuration file and it still ran fine. I am guessing that annotation must be the default.

        Comment


        • #5
          Originally posted by mrobinson View Post
          BTW, I removed all references to <context:... in the configuration file and it still ran fine. I am guessing that annotation must be the default.
          That is unfortunately an incorrect assumption: annotation-driven dependency injection is not the default with Spring ApplicationContexts.

          The issue is that the Spring TestContext Framework automatically enables annotation-driven DI for application contexts loaded by the testing framework (i.e., configured via @ContextConfiguration). See this JIRA issue for details: http://jira.springframework.org/browse/SPR-6050

          Thus, although your tests may pass, that will not be the case for the application when run outside of the test environment. The solution is to enable annotation-driven DI via either <context:annotation-config ... /> or <context:component-scan ... />.

          Regards,

          Sam

          Comment


          • #6
            That is very good to know. Thanks for correcting my assumption.

            Comment


            • #7
              i have the same exception, spring can't autowire some service and in the ContextConfiguration i am loading the default applicationContext.xml that the (functional) application is using, it seems to me that its not creating the beans so i cant autowire them.

              i created the beans manually [ctx.getAutowireCapableBeanFactory().createBean(MyD AO.class);]
              and it create them fine but i cant inyect the sessionFactory...

              could be coz the aplication is annotation managed so the beans are created througt annotations and JUnit does not recognize them o.O?
              Last edited by White_King; Apr 4th, 2012, 12:11 PM.

              Comment

              Working...
              X