I first did not mention what was the key component of this issue: I am using TestNG here.
I have a DAO layer performing persistence. It works fine as part of my little web app (I have a classic Controller, Service, DAO layers design). I can update this question with my XMLs if required.
My Service layer
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public GoodVibeUserDetails getUser(String username) throws UsernameNotFoundException {
GoodVibeUserDetails user = userDao.getDetailsRolesAndImagesForUser(username);
return user;
}
// more methods...
}
My DAO layer
@Repository
public class UserDaoImplHibernate implements UserDao {
@Autowired
private SessionFactory sessionFactory;
// My methods using sessionFactory & "talking" to the Db via the sessionFactory
}
And here is my Test Class
@Component
public class UserDaoImplHibernateTests{
@Autowired
private UserDao userDao;
private GoodVibeUserDetails user;
@BeforeMethod
public void beforeEachMethod() throws ParseException{
user = new GoodVibeUserDetails();
user.setUsername("adrien");
user.setActive(true);
// & so on...
}
/*
* When everything is fine - test cases
*/
@Test
public void shouldAcceptRegistrationAndReturnUserWithId() throws Exception{
assertNotNull(userDao) ;
user = userDao.registerUser(user);
assertNotNull(user.getId()) ;
}
// more test cases...
}
But for my test class the Autowiring, userDao
always returns Null, I'm only starting to do tests in Spring and I'm a bit lost. Any pointers are welcome.
Latest edit after Boris Treukhov's answer
import ...
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;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
public class UserDaoImplHibernateTests{
@Autowired
@Qualifier("userDao")
private UserDao userDao;
private GoodVibeUserDetails user;
@BeforeMethod
public void beforeEachMethod() throws ParseException{
user = new GoodVibeUserDetails();
user.setUsername("adrien");
user.setActive(true);
// & so on...
}
/*
* When everything is fine - test cases
*/
@Test
public void shouldAcceptRegistrationAndReturnUserWithId() throws Exception{
assertNotNull(userDao) ;
user = userDao.registerUser(user);
assertNotNull(user.getId()) ;
}
// more test methods...
}
And this is my applicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" >
<!-- the application context definition scans within the base package of the application -->
<!-- for @Components, @Controller, @Service, @Configuration, etc. -->
<context:annotation-config />
<context:component-scan base-package="com.goodvibes" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}" p:password="${jdbc.password}" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">${jdbc.show_sql}</prop>
<prop key="hibernate.connection.SetBigStringTryClob">true</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
[...]
</beans>
I did not add a repository-config.xml as this should be enough to access userDao
. I still get userDao equal null though.
Thanks in advance
If you create unit tests, Spring IoC functionality is unavailable(as it was intended by the framework designers), because you are testing your objects in isolation(i.e. you are mocking only minimal set of interfaces which are required for the test to complete). In this case you should inject your mock repository manually, for example in @Before test initialization method. The whole idea is that your classes only depend on interfaces, so basically Spring container evaluates which class to use as the interface implementation, but when you create a unit test you need to have a strict control of which interface methods were called(and have a minimal set of dependencies), that is why you perform the injection manually.
If you are doing integration testing, you should have a Spring IoC container instance up and running, for this to work you should use jUnit(assuming that you are using jUnit) specific test runner, as it described in the Spring documentation on testing.
So, returning to the question, you have what looks like a simple unit test to jUnit, and the Spring container is not used. So, if you are going to use Spring TestContext framework, you should have something like
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/path-to-app-config.xml", "/your-test-specific-config.xml"})
public class UserDaoImplHibernateTests
instead of @Component
.
update in TestNg case I think it should be (I used Spring Dependency Injection with TestNG as the reference)
@ContextConfiguration(locations={"/path-to-app-config.xml", "/your-test-specific-config.xml"})
public class UserDaoImplHibernateTests extends AbstractTestNGSpringContextTests
See also: What is the difference between integration and unit tests?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With