I'm developing a spring application using JavaFX (I'm NOT using Spring MVC) and I have standard separation of concerns with controllers - services - DAOs. I'm using JdbcTemplate. I'm willing to write down jUnit tests for one of my services (I have already did it for some of them). The specific thing is that the service is autowiring two DAOs(one of which uses transactions itself) and furthermore it has one method, which is @Transactional
. This is how my test exactly looks:
package org.impactvolunteers.management.service.impl;
imports ...;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:testContext.xml" })
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class RegisterVolunteerServiceImplTest extends
AbstractRegisterVolunteerServiceTest {
@Autowired
private RegisterVolunteerService registerVolunteerService;
@Before
public void setUp() {
setRegisterVolunteerService(registerVolunteerService);
}
}
And my Service implementation:
package org.impactvolunteers.management.service.impl;
imports ...;
public class RegisterVolunteerServiceImpl implements RegisterVolunteerService {
@Autowired
private VolunteerDao volunteerDao;
@Autowired
private UserDao userDao;
@Transactional(rollbackFor = { ServiceException.class,
ValidationException.class })
public Volunteer registerVolunteer(User user, Volunteer volunteer)
throws ServiceException, ValidationException {
UserValidator.validateData(user);
VolunteerValidator.validateData(volunteer);
try {
User ret = userDao.create(user);
volunteer.setUser(ret);
return volunteerDao.create(volunteer);
} catch (PersistenceException e) {
throw new ServiceException(e.getMessage(), e);
}
}
}
And in application-Context:
<context:component-scan base-package="org.impactvolunteers.management"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
...
<bean id="registerVolunteerService" class="org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImpl" >
</bean>
Here is the error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImplTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.impactvolunteers.management.service.RegisterVolunteerService org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImplTest.registerVolunteerService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.impactvolunteers.management.service.RegisterVolunteerService] 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:288) ............ Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.impactvolunteers.management.service.RegisterVolunteerService] 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:486) ... 28 more
And my test-Context.xml:
<context:annotation-config/>
<context:component-scan base-package="org.impactvolunteers.management"/>
<bean id="jdbc" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Spring JDBC Utility for in-memory database -->
<jdbc:embedded-database id="dataSource" type="HSQL"/>
Two strange things I noticed:
@Transactional
annotations, where some of the DAOs under it do (VolunteerDaoImpl
which implements VolunteerDao
does contain a @Transactional
annotation).The class RegisterVolunteerServiceImpl
must be annotated as service.
If the class is not annotated as a service it will not befound by the component-scan. So the bean with the name is not instanciated and can not be autowired.
In your main application-context you add the bean without component-scan
<bean id="registerVolunteerService" class="org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImpl" >
</bean>