Pregunta

Writing Junit Tests for my spring application. Because I am new at this I tried starting off by writing a Unit Test for a DAO class that I know works (ran it in JBoss). However, I cannot get it to work as a Unit Test in Eclipse. I keep getting an "Error creating bean... Could not autowire field: NoSuchBeanDefinition".

I saw errors similar to this on StackOverflow and other sites and it always ended up being a syntax error or attempting to autowire the Implementation of the interface as opposed to the Interface, etc. I don't see any of those errors with my code.

I did download Spring-test.jar separately from the Spring configuration that came with the project. Both are from Spring 2.5 however, so I don't think that should be an issue :/

Eclipse comes bundled with JUnit 4.8 and Spring Unit Test doesn't work with that so I downgraded my JUnit to use 4.4

One thing to consider... if you look at the code for my Unit Test you will notice that I autowire two fields: a SimpleJdbcTemplate at the Query Service I want to test. Well if I remove the DrugDao and all references to it, then the SimpleJdbcQuery auto-wires just fine.

Here is the stacktrace for your review:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tst.hcps.glucosemanagement.dataaccess.DrugDaoTest': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.hcps.glucosemanagement.repository.meds.DrugDao tst.hcps.glucosemanagement.dataaccess.DrugDaoTest.dQuery; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.hcps.glucosemanagement.repository.meds.DrugDao] is defined: Unsatisfied dependency of type [interface com.hcps.glucosemanagement.repository.meds.DrugDao]: expected at least 1 matching bean
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:243)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:959)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:329)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:127)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:85)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:95)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:139)
    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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.hcps.glucosemanagement.repository.meds.DrugDao tst.hcps.glucosemanagement.dataaccess.DrugDaoTest.dQuery; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.hcps.glucosemanagement.repository.meds.DrugDao] is defined: Unsatisfied dependency of type [interface com.hcps.glucosemanagement.repository.meds.DrugDao]: expected at least 1 matching bean
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:435)
    at org.springframework.beans.factory.annotation.InjectionMetadata.injectFields(InjectionMetadata.java:105)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:240)
    ... 18 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.hcps.glucosemanagement.repository.meds.DrugDao] is defined: Unsatisfied dependency of type [interface com.hcps.glucosemanagement.repository.meds.DrugDao]: expected at least 1 matching bean
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:613)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:412)
    ... 20 more

Here is the Interface and Implementation:

DrugDao.java

package com.hcps.glucosemanagement.repository.meds;

import java.util.List;

import com.hcps.glucosemanagement.domain.meds.Drug;

public interface DrugDao {

    public List<Drug> searchDrugsByPrimaryName(String facilityId, String name);

    public List<Drug> searchDrugs(String facilityId, String primaryName, String secondaryName);

}

SpringJdbcDrugQuery.java

package com.hcps.glucosemanagement.repository.meds;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.stereotype.Service;

import com.hcps.glucosemanagement.domain.meds.Drug;
import com.hcps.glucosemanagement.repository.DaoOperations;

@Service
public class SpringJdbcDrugQuery extends DaoOperations implements DrugDao {

private static final Logger logger = Logger.getLogger(SpringJdbcDrugQuery.class);

public List<Drug> searchDrugsByPrimaryName(String facilityId, String name) 
{
    return searchDrugs(facilityId, name, null);
}

public List<Drug> searchDrugs(String facilityId, String primaryName, String secondaryName) 
{
    List<Drug> results = null;

    StringBuffer sql = new StringBuffer();    
    HashMap<String, Object> namedParameters = new HashMap<String, Object>();

    if(primaryName==null) return null;

    sql = new StringBuffer();

    sql.append("SELECT");
            ...
        results = simpleJdbcTemplate.query(sql.toString(), new DrugMapper(), 


    return results;
}

private static final class DrugMapper implements ParameterizedRowMapper<Drug> 
{

    public Drug mapRow(ResultSet rs, int rowNum) throws SQLException {
        Drug drug = new Drug();
        drug.setFacilityId(rs.getString("FACILITY_ID"));
        drug.setPrimaryName(rs.getString("PRIMARY_NAME"));
        drug.setSecondaryName(rs.getString("SEC_NAME"));
        return drug;
    }

}
}

DrugDaoTest2.java (located in a separate source folder at first, then tried it in the same folder)

package com.hcps.glucosemanagement.repository.meds;

import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.hcps.glucosemanagement.domain.meds.Drug;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
        "classpath:common-test.xml"
})
public class DrugDaoTest2 {

    @Autowired
    DrugDao dQuery;
    @Autowired
    SimpleJdbcTemplate queryTemplate;

    @Test public void glucoseFetch() {
        List<Drug> rslts = dQuery.searchDrugsByPrimaryName(null, "INSU*");
        assertTrue(rslts.size()>0);
        int i=0;
        System.out.println(i);

    }

    public void setDrugDao(DrugDao drugDao) {
        this.dQuery = drugDao;
    }
}

common-test.xml

<?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:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
>

   <!--
   Test configuration for Spring/JUnit Testing
   -->

  <bean id="contextApplicationContextProvider" class="com.hcps.glucosemanagement.spring.ApplicationContextProvider" />

  <bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="beans">
      <map>
        <entry key="bean:name=Log4jJmxServiceMBean" value-ref="glucosemanagement.Log4jJmxService" />
      </map>
    </property>
  </bean>
  <bean id="glucosemanagement.Log4jJmxService" class="com.hcps.glucosemanagement.logging.Log4jJmxService" />

  <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="/WEB-INF/messages" />
  </bean>

  <bean id="parameterMappingInterceptor" class="org.springframework.web.portlet.handler.ParameterMappingInterceptor" />
  <bean id="viewResolverCommon" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
    p:order="2"
    p:cache="false"
    p:viewClass="org.springframework.web.servlet.view.JstlView"
    p:prefix="/WEB-INF/jsp/"
    p:suffix=".jsp"
  />

  <bean id="defaultExceptionHandler" class="org.springframework.web.portlet.handler.SimpleMappingExceptionResolver">
    <property name="defaultErrorView" value="../error"/>
    <property name="exceptionMappings">
      <props>
        <prop key="javax.portlet.PortletSecurityException">notAuthorized</prop>
        <prop key="javax.portlet.UnavailableException">notAvailable</prop>
      </props>
    </property>
  </bean>

  <bean id="simpleParameterJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
    <constructor-arg ref="hciDataSource" />
  </bean>

  <bean id="hciDataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@//vir-tst.com:1521/qar01.world" />
    <property name="username" value="ccuser" />
    <property name="password" value="bueno" />
    <property name="maxActive" value="30" />
    <property name="maxWait" value="30" />
    <property name="maxIdle" value="30" />
  </bean>

</beans>
¿Fue útil?

Solución

My mistake: there was another Spring Configuration file referenced elsewhere that I missed. Adding this field and defining setters in my Unit Test for any autowired fields solved the problem.

I am using this checklist now when these types of errors occur:

  • Make sure that implementing class of Interface type uses “@Service” annotation
  • Make sure beans are configured properly in the XML:
  • Simplest way is to use:

<context:component-scan base-package="com.customization.packagename" />

  • This adds all classes under the package name
  • Or create XML Bean Definitions

Otros consejos

I had the similar issue and found that while I could AutoWire classes successfully in Eclipse, surefire required only interfaces to be AutoWired. Especially this occurs only when using Cobertura for instrumenting, so pretty sure there is something wrong with the proxy generation. For now, I have just introduced a new interface as it was appropriate for my use-case but there should definitely be another appropriate solution.

Add a bean definition of type SpringJdbcDrugQuery to common-test.xml

I encounter this problem too, and I just add setter, then it works well.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top