[英]Autowired bean in spock test null after downgrading spring from 4.3.x to 3.2.x
[英]Spring 3.2.x: Integration test fails when injecting concrete bean
Spring 3.2.6-RELEASE和JUnit 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.