繁体   English   中英

Spring 3.2.x:注入混凝土bean时集成测试失败

[英]Spring 3.2.x: Integration test fails when injecting concrete bean

Spring 3.2.6-RELEASEJUnit 4.11

我一直在尝试使用spring 3.2.6-RELEASE编写集成测试,由于某种原因,我的bean无法注入测试类中。

当我删除扩展AbstractSpringService部分时,代码可以正常工作。 但是,在我的AbstractSpringService中丢失所有可重用的代码将是可耻的。

当我删除配置文件的持久性部分时,该代码也适用:

<context:property-placeholder location="classpath*:*.properties"/>
<context:annotation-config/>
<context:component-scan base-package="br.eti.danielcamargo.hsnpersonal.model"  />

对这里发生的事情有任何想法吗?

这是要测试的服务:

import br.eti.danielcamargo.hsnpersonal.domain.entities.Programa;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;

@Service
public class ProgramaService extends AbstractSpringService<Programa> {

    @PersistenceContext
    private EntityManager em;

    @PostConstruct
    private void setup() {
        System.out.println("Creating programaService");
    }

    public ProgramaService() {
        super(Programa.class);
    }

    @Override
    public EntityManager getEntityManager() {
        return em;
    }

}

是父母:

import br.eti.danielcamargo.commons.business.AbstractService;
import br.eti.danielcamargo.commons.business.BusinessException;
import br.eti.danielcamargo.commons.domain.AbstractEntity;
import org.springframework.transaction.annotation.Transactional;

public abstract class AbstractSpringService<ENTITY extends AbstractEntity> extends AbstractService<ENTITY> {

    public AbstractSpringService(Class<ENTITY> entityClass) {
        super(entityClass);
    }

    @Override
    @Transactional
    public ENTITY save(ENTITY entity) throws BusinessException {
        return super.save(entity);
    }

    @Override
    @Transactional
    public void remove(ENTITY entity) {
        super.remove(entity);
    }

}

和祖父母:

import br.eti.danielcamargo.commons.domain.AbstractEntity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;

public abstract class AbstractService<ENTITY extends AbstractEntity> implements
    Serializable {

    private static final long serialVersionUID = 1L;

    private static final Validator validator;

    static {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    public abstract EntityManager getEntityManager();
    private final Class<ENTITY> entityClass;

    public AbstractService(Class<ENTITY> entityClass) {
        this.entityClass = entityClass;
    }

    public void validate(ENTITY entity) throws BusinessException {
        Set<ConstraintViolation<ENTITY>> constraintViolations = validator
            .validate(entity);
        if (!constraintViolations.isEmpty()) {
            List<ValidationOccurrence> ocorrencias = new ArrayList<ValidationOccurrence>();

            for (ConstraintViolation<ENTITY> constraintViolation : constraintViolations) {
                ocorrencias.add(new ValidationOccurrence(true, constraintViolation
                    .getRootBeanClass().getSimpleName()
                    + "."
                    + constraintViolation.getPropertyPath(),
                    constraintViolation.getMessage(), constraintViolation
                    .getInvalidValue()));
            }

            throw new BusinessException(ocorrencias);
        }
    }

    public ENTITY save(ENTITY entity) throws BusinessException {
        validate(entity);
        entity = getEntityManager().merge(entity);
        afterSave(entity);
        return entity;
    }

    public void afterSave(ENTITY entity) {
    }

    public ENTITY get(Long id) {
        TypedQuery<ENTITY> query = null;
        try {
            query = getEntityManager().createNamedQuery(
                "get" + entityClass.getSimpleName(), entityClass);
        } catch (IllegalArgumentException e) {
            return getEntityManager().find(entityClass, id);
        }
        try {
            query.setParameter("id", id);
        } catch (IllegalArgumentException e) {
            query.setParameter(1, id);
        }
        query.setMaxResults(1);
        List<ENTITY> result = query.getResultList();
        return result.isEmpty() ? null : result.get(0);
    }

    public List<ENTITY> getAll() {
        TypedQuery<ENTITY> query = null;
        try {
            query = getEntityManager().createNamedQuery(
                "getAll" + entityClass.getSimpleName(), entityClass);
        } catch (IllegalArgumentException e) {
            CriteriaQuery<ENTITY> cq = getEntityManager().getCriteriaBuilder()
                .createQuery(entityClass);
            cq.select(cq.from(entityClass));
            query = getEntityManager().createQuery(cq);
        }
        List<ENTITY> result = query.getResultList();
        return result;
    }

    public void remove(ENTITY entity) {
        entity = getEntityManager().find(entityClass, entity.getId());
        getEntityManager().remove(entity);
    }
}

这是测试:

import javax.annotation.PostConstruct;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testContext.xml")
public class ProgramaServiceTest {

    @Autowired
    private ProgramaService programaService;

    @PostConstruct
    private void setup() {
        System.out.println("Creating programa test");
    }

    @Test
    public void test() {
        Assert.assertNotNull(programaService);
    }

}

这是配置文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <context:property-placeholder location="classpath*:*.properties"/>

    <context:annotation-config/>

    <context:component-scan base-package="br.eti.danielcamargo.hsnpersonal.model"  />

    <!-- PERSISTENCE -->
    <bean id="appDS" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <!-- Connection properties -->
        <property name="driverClass" value="${database.driverClassName}" />
        <property name="jdbcUrl" value="${database.url}" />
        <property name="user" value="${database.username}" />
        <property name="password" value="${database.password}" />
        <!-- Pool properties -->
        <property name="minPoolSize" value="1" />
        <property name="maxPoolSize" value="2" />
        <property name="maxStatements" value="50" />
        <property name="idleConnectionTestPeriod" value="3000" />
        <property name="loginTimeout" value="300" />
    </bean>

    <bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="defaultDataSource" ref="appDS" />
    </bean>
    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitManager" ref="persistenceUnitManager" />
        <property name="persistenceUnitName" value="${database.persistentUnitName}" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.import_files">${database.imports}</prop>
            </props>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />

</beans>

这是例外:

[HSN-PERSONAL] [INFO]: [23:17:34,208] [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - [Loading XML bean definitions from class path resource [testContext.xml]]
[HSN-PERSONAL] [INFO]: [23:17:34,414] [org.springframework.context.support.GenericApplicationContext] - [Refreshing org.springframework.context.support.GenericApplicationContext@41942912: startup date [Mon Feb 03 23:17:34 BRST 2014]; root of context hierarchy]
[HSN-PERSONAL] [INFO]: [23:17:34,527] [org.springframework.context.support.PropertySourcesPlaceholderConfigurer] - [Loading properties file from file [D:\development\projects\hsn-personal\target\test-classes\database.properties]]
[HSN-PERSONAL] [INFO]: [23:17:34,534] [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor] - [JSR-330 'javax.inject.Inject' annotation found and supported for autowiring]
[HSN-PERSONAL] [INFO]: [23:17:34,603] [com.mchange.v2.log.MLog] - [MLog clients using log4j logging.]
[HSN-PERSONAL] [INFO]: [23:17:34,705] [com.mchange.v2.c3p0.C3P0Registry] - [Initializing c3p0-0.9.2.1 [built 20-March-2013 10:47:27 +0000; debug? true; trace: 10]]
[HSN-PERSONAL] [INFO]: [23:17:34,845] [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] - [Building JPA container EntityManagerFactory for persistence unit 'hsnpu']
[HSN-PERSONAL] [INFO]: [23:17:34,992] [org.hibernate.annotations.common.Version] - [HCANN000001: Hibernate Commons Annotations {4.0.2.Final}]
[HSN-PERSONAL] [INFO]: [23:17:34,998] [org.hibernate.Version] - [HHH000412: Hibernate Core {4.2.2.Final}]
[HSN-PERSONAL] [INFO]: [23:17:35,000] [org.hibernate.cfg.Environment] - [HHH000206: hibernate.properties not found]
[HSN-PERSONAL] [INFO]: [23:17:35,002] [org.hibernate.cfg.Environment] - [HHH000021: Bytecode provider name : javassist]
[HSN-PERSONAL] [INFO]: [23:17:35,023] [org.hibernate.ejb.Ejb3Configuration] - [HHH000204: Processing PersistenceUnitInfo [
    name: hsnpu
    ...]]
[HSN-PERSONAL] [INFO]: [23:17:35,170] [org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator] - [HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider]
[HSN-PERSONAL] [INFO]: [23:17:35,236] [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] - [Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge5zz8z1xhw46nud6z0y|5c07481f, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> org.postgresql.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge5zz8z1xhw46nud6z0y|5c07481f, idleConnectionTestPeriod -> 3000, initialPoolSize -> 3, jdbcUrl -> jdbc:postgresql://127.0.0.1:5432/hsn, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 2, maxStatements -> 50, maxStatementsPerConnection -> 0, minPoolSize -> 1, numHelperThreads -> 3, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]]
[HSN-PERSONAL] [INFO]: [23:17:35,503] [org.hibernate.dialect.Dialect] - [HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect]
[HSN-PERSONAL] [INFO]: [23:17:35,512] [org.hibernate.engine.jdbc.internal.LobCreatorBuilder] - [HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException]
[HSN-PERSONAL] [INFO]: [23:17:35,697] [org.hibernate.engine.transaction.internal.TransactionFactoryInitiator] - [HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory]
[HSN-PERSONAL] [INFO]: [23:17:35,702] [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] - [HHH000397: Using ASTQueryTranslatorFactory]
[HSN-PERSONAL] [INFO]: [23:17:35,743] [org.hibernate.validator.internal.util.Version] - [HV000001: Hibernate Validator 4.3.1.Final]
[HSN-PERSONAL] [INFO]: [23:17:36,066] [org.hibernate.tool.hbm2ddl.SchemaExport] - [HHH000227: Running hbm2ddl schema export]
[HSN-PERSONAL] [INFO]: [23:17:39,131] [org.hibernate.tool.hbm2ddl.SchemaExport] - [HHH000230: Schema export complete]
[HSN-PERSONAL] [INFO]: [23:17:39,197] [org.springframework.beans.factory.support.DefaultListableBeanFactory] - [Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5839cb0: defining beans [org.springframework.context.support.PropertySourcesPlaceholderConfigurer#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,programaService,appDS,persistenceUnitManager,entityManagerFactory,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy]
Creating programaService
[HSN-PERSONAL] [ERROR]: [23:17:39,251] [org.springframework.test.context.TestContextManager] - [Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@619130e2] to prepare test instance [br.eti.danielcamargo.hsnpersonal.model.services.ProgramaServiceTest@3207779]]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'br.eti.danielcamargo.hsnpersonal.model.services.ProgramaServiceTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.eti.danielcamargo.hsnpersonal.model.services.ProgramaService br.eti.danielcamargo.hsnpersonal.model.services.ProgramaServiceTest.programaService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [br.eti.danielcamargo.hsnpersonal.model.services.ProgramaService] 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)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1146)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:376)
    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:312)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.eti.danielcamargo.hsnpersonal.model.services.ProgramaService br.eti.danielcamargo.hsnpersonal.model.services.ProgramaServiceTest.programaService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [br.eti.danielcamargo.hsnpersonal.model.services.ProgramaService] 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)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:517)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
    ... 26 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [br.eti.danielcamargo.hsnpersonal.model.services.ProgramaService] 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)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:988)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:858)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489)
    ... 28 more
[HSN-PERSONAL] [INFO]: [23:17:39,262] [org.springframework.context.support.GenericApplicationContext] - [Closing org.springframework.context.support.GenericApplicationContext@41942912: startup date [Mon Feb 03 23:17:34 BRST 2014]; root of context hierarchy]
[HSN-PERSONAL] [INFO]: [23:17:39,263] [org.springframework.beans.factory.support.DefaultListableBeanFactory] - [Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5839cb0: defining beans [org.springframework.context.support.PropertySourcesPlaceholderConfigurer#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,programaService,appDS,persistenceUnitManager,entityManagerFactory,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy]
[HSN-PERSONAL] [INFO]: [23:17:39,269] [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] - [Closing JPA EntityManagerFactory for persistence unit 'hsnpu']

通过添加解决了问题

<aop:aspectj-autoproxy proxy-target-class="true" />

到配置文件。 代理目标类的文档说:

“是否要创建基于类的(CGLIB)代理?默认情况下,将创建基于Java接口的标准代理。”

我怀疑当Spring创建这个bean时,它是父类类型的,而不是子类的。 因此,当您请求自动装配子类时,它无法强制转换/无法告诉该父类有一个。

如果您使用父类自动装配,它应该可以工作:

@Autowired private AbstractSpringService programaService;

如果确实需要使用子类的成员,则可以强制转换它。

如果您有多个实现抽象的bean,则可以使用@Qualifier选择一个特定的bean。

@Autowired @Qualifier("foo") private AbstractSpringService programaService;

在您的服务班级

@Service("foo")
public class Blah extends AbstractSpringService {
  ...

其他解决方案可能是避免使用@Service并在xml中声明bean。

我希望有一个比这些更优雅的解决方案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM