Suppose I have these two parts of XML Spring config in two distinct files;
//daoContext.xml
<bean id="myDao" class="com.MyDao"/>
//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
<constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
And there is the test class:
#ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
#Test
public void testMyTestable() {
//...
}
}
Now, what I want is to be able to mock MyDao class and inject is somehow into MyLogic which is to be injected in BaseLogicTest so I can use MyLogic with a mocked MyDao. Is this possible using Spring/Spring Test?
The simplest solution is load all your xml. And manually replace dependence in test case.
#ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
#Before
public void injectTestDoubles() {
myLogic.setMyDao(...);
}
#DirtiesContext
#Test ...//test methods
}
But this corrupts the application context, so you need #DirtiesContext if you need "real" myDao in other test case sharing the same application context.
The most popular solution (my personal opinion :P ) is using mockito and a test-specific xml.
//daoContext.xml
<bean id="myDao" class="com.MyDao"/>
//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
<constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
//test-logicContext.xml
<bean id="myDao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.MyDao" />
</bean>
#ContextConfiguration({"logicContext.xml", "test-logicContext.xml"})
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
#Autowired
private MyDao myDao;//retrieve mock so you could define expectations
#Test //test methods
#After public void clearMocks() {
Mockito.reset(myDao);//this is important if you have several test methods
}
}
And this solution works for other mock framework like easyMock.
You can do this by creating a FactoryBean to create the MyDao (or any) mock to be injected into your MyLogic instance.
public class FactoryBeanForMocks<T> implements FactoryBean<T> {
private Class<T> mockClass;
public FactoryBeanForMocks(Class<T> mockClass) {
super();
this.mockClass = mockClass;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(mockClass);
}
#Override
public Class<?> getObjectType() {
return mockClass;
}
#Override
public boolean isSingleton() {
return true;
}
}
Make the factory bean entry into your logicContext.xml so that a mock of MyDao can be injected into MyLogic:
//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
<constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
<bean id="myDao" class="x.y.z.FactoryBeanForMocks">
<constructor-arg name="mockClass" value="x.y.MyDao"></constructor-arg>
</bean>
And this is your test class:
#ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
//You can inject the mock myDao into it so that you can stub/verify method calls on it
#Autowired
private MyDao myDao;
#Test
public void testMyTestable() {
//...
when(myDao.process()).thenReturn("a");//stubbing myDao.process()
assertEquals("a", myLogic.processRequest());// assuming myLogic.processRequest() calls myDao.process()
}
}
Related
I am new to spring. I am attempting to autowire TestDAO without setter method. But i failed to autowire.
System.out.println("TestClass.testDAO "+testDAO); It returns null.
Kindly help me to unlock.
My xml config :
<context:component-scan base-package="com.test" />
<context:annotation-config/>
<bean id="testClass" class="com.test.TestClass" autowire="byName">
</bean>
Java classes :
#Component
public class TestClass {
#Autowired(required=true)
public TestDAO testDAO = null;
{
System.out.println("TestClass.testDAO "+testDAO);
}
}
#Repository
public class TestDAO{
}
Here's an example about how to fix your code:
#Component
public class TestClass {
#Autowired(required=true)
public TestDAO testDAO;
// When someone calls this method, the testDao component should
// be initialized with TestDAO instance.
public void someMethod(){
System.out.println("TestClass.testDAO "+testDAO);
}
}
public interface TestDAO extends JpaRepository<MyEntity, Long>{
}
Also, you could use the #Autowired annotation in a constructor.
#Component
public class TestClass {
public TestDAO testDAO;
#Autowired
public TestClass(TestDAO testDAO){
this.testDAO = testDAO;
System.out.println("TestClass.testDAO "+testDAO);
}
}
Hope it helps,
I have two classes:
public MyService {
#Autowired
private MyDao myDao;
private List<Items> list;
#PostConstruct
private void init(){
list = myDao.getItems();
}
}
Now I'm wanting to involve MyService in a unit test, and so I'll mock the behaviour MyDao.
XML:
<bean class = "com.package.MyService">
<bean class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.MyDao"/>
</bean>
<util:list id="responseItems" value-type="com.package.Item">
<ref bean="item1"/>
<ref bean="item2"/>
</util:list>
Unit Test:
#ContextConfiguration("/test-context.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
#Autowired
MyService myService
#Autowired
MyDao myDao;
#Resource
#Qualifier("responseItems")
private List<Item> responseItems;
#Before
public void setupTests() {
reset(myDao);
when(myDao.getItems()).thenReturn(responseItems);
}
}
The problem with this is that the MyService bean is created, and its #PostConstruct bean called before the mocked behaviour is defined.
How can I either define the mocked behaviour in the XML or delay #PostConstruct until after the unit test setup?
I have same kind of requirement in my project. where i need to set a string using #PostConstructor and I did not want to ran spring context or in other words I want simple mock. My requirement was follow:
public class MyService {
#Autowired
private SomeBean bean;
private String status;
#PostConstruct
private void init() {
status = someBean.getStatus();
}
}
Solution:
public class MyServiceTest(){
#InjectMocks
private MyService target;
#Mock
private SomeBean mockBean;
#Before
public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
MockitoAnnotations.initMocks(this);
when(mockBean.getStatus()).thenReturn("http://test");
//call post-constructor
Method postConstruct = MyService.class.getDeclaredMethod("init",null); // methodName,parameters
postConstruct.setAccessible(true);
postConstruct.invoke(target);
}
}
MyDao sounds like it is an abstraction of an external system. Generally external systems shouldn't be called in #PostConstruct methods. Instead have your getItems() called by another method in MyService.
Mockito injections will take place after the Spring initiation at which point the mock isn't working as you see. You cannot delay the #PostConstruct. To beat this and have the load run automatically have MyService implement SmartLifecycle and call getItems() in start().
Use annotation in dao
#Repository("testDao")
public class TestDaoImpl extends JdbcDaoSupport implements BaseDao{
#Override
public Object addObject(String sqlid, Object obj) {
// TODO Auto-generated method stub
return null;
}
Caused by: java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
I do not want to use :
<bean id="termsDao" class="com.manage.base.dao.impl.TestDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
this code set in xml, and “jdbcTemplate” has been defined in other “spring-xml”。
How to solve this problem by an annotation :“'dataSource' or 'jdbcTemplate' is required”
You can use one of the below approaches. The first one - taking a dataSource is preferred / recommended as you don't expose a SpringFramework class in your public interface. Both will work.
#Repository("testDao")
public class TestDaoImpl extends JdbcDaoSupport implements BaseDao{
#Autowired
TestDaoImpl(DataSource dataSource) {
setDataSource(dataSource);
}
}
Or
#Repository("testDao")
public class TestDaoImpl extends JdbcDaoSupport implements BaseDao{
#Autowired
TestDaoImpl(JDBCTemplate template) {
setJdbcTemplate(template);
}
}
I even feel injecting datasource as a constructor to your DAO is a unnecessary coding step.
Why not inject datasource in Spring config XML into JDBC template and just get jdbctTemplate
object in every DAO.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
and let your DAO extend JDBCSupport class.
public class PersonDao extends JdbcDaoSupport{
public List<Person> selectAll(){
String selectAllSql = "SELECT * FROM PERSON;";
return getJdbcTemplate().query(selectAllSql, new PersonRowMapper());
........
}
}
Full example :
http://www.studytrails.com/frameworks/spring/spring-jdbc-dao-support.jsp
Given the following MyConstructorClass:
#Component
public class MyConstructorClass{
MyObj var;
public MyConstructorClass( MyObj constrArg ){
this.var = var;
}
...
}
How can I autowire a field that requires a constructor argument from a previously #Autowired field? Below is an example.
Note - this question, I believe, is similar to this one, except that my constructor argument is not a String. This code sample is slightly modified from this question.
#Service
public class MyBeanService{
#Autowired
CustomObject customObj; // no arguments to constructor
#Autowired
MyConstructorClass myConstructorClass; // requires `customObj` as an argument
....
}
How can I modify MyBeanService to properly construct myConstructorClass with customObj?
You just need to annotated the constructor of MyConstructorClass with #Autowired:
#Component
public class MyConstructorClass {
final private CustomObject customObj;
#Autowired
public MyConstructorClass(CustomObject customObj) {
this.customObj = customObj;
}
}
Another alternative, (without adding the #Autowired constructor to MyConstructorClass) is to use a #Configuration bean:
#Configuration
public class MyConfiguration {
#Bean
public CustomObject customObj() {
return customObj;
}
#Bean
public MyConstructorClass myConstructorClass() {
return new MyConstructorClass(customObj());
}
#Bean
public MyBeanService myBeanService() {
return new MyBeanService();
}
}
you can use the <constructor-arg> in your servlet
<bean id="myConstructorClass" class="package.MyConstructorClass">
<constructor-arg>
<bean class="package.CustomObject"/>
</constructor-arg>
</bean>
If this is the only place you need to use that class could use #PostConstruct to instantiate itself. I think there is a better solution, but this is off the top of my head.
#Service
public class MyBeanService{
#Autowired
CustomObject customObj;
MyConstructorClass myConstructorClass;
#PostConstruct
public void construct()
{
myConstructorClass = new MyConstructorClass(customObj);
}
}
In the constructor, you can refer to other beans defined in Spring.
<bean id="myConstructorClass" class="package.MyConstructorClass">
<constructor-arg index="0" ref="customObj"/>
</bean>
One of the strongest accents of the Spring framework is the Dependency Injection concept. I understand one of the advices behind that is to separate general high-level mechanism from low-level details (as announced by Dependency Inversion Principle).
Technically, that boils down to having a bean implementation to know as little as possible about a bean being injected as a dependency, e.g.
public class PrintOutBean {
private LogicBean logicBean;
public void action() {
System.out.println(logicBean.humanReadableDetails());
}
//...
}
<bean class="PrintOutBean">
<property name="loginBean" ref="ShoppingCartBean"/>
</bean>
But what if I wanted to a have a high-level mechanism operating on multiple dependent beans?
public class MenuManagementBean {
private Collection<Option> options;
public void printOut() {
for (Option option:options) {
// do something for option
}
//...
}
}
I know one solution would be to use #Autowired annotation in the singleton bean, that is...
#Autowired
private Collection<Option> options;
But doesn't it violate the separation principle? Why do I have to specify what dependents to take in the very same place I use them (i.e. MenuManagementBean class in my example)?
Is there a way to inject collections of beans in the XML configuration like this (without any annotation in the MMB class)?
<bean class="MenuManagementBean">
<property name="options">
<xxx:autowire by-type="MyOptionImpl"/>
</property>
</bean>
Old question and in Spring 3.1 it is possible:
public class PluginPrototypeTest extends ASpringWebTest {
#Autowired
Collection<IDummyRepo> repos;
#Test
public void cacheTest() {
assertNotNull(repos);
assertEquals(2, repos.size());
for(IDummyRepo r: repos){
System.out.println(r.getName());
}
}
}
#Repository
public class DummyRepo implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo";
}
}
#Repository
public class DummyRepo2 implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo2";
}
}
There's no out-of-the-box facility to do this, no. However, if you want a way of collecting all beans of a given type into a collection, without using an #Autowired list, then it's easy to write a custom FactoryBean to do it for you:
public class BeanListFactoryBean<T> extends AbstractFactoryBean<Collection<T>> {
private Class<T> beanType;
private #Autowired ListableBeanFactory beanFactory;
#Required
public void setBeanType(Class<T> beanType) {
this.beanType = beanType;
}
#Override
protected Collection<T> createInstance() throws Exception {
return beanFactory.getBeansOfType(beanType).values();
}
#Override
public Class<?> getObjectType() {
return Collection.class;
}
}
and then
<bean class="MenuManagementBean">
<property name="options">
<bean class="BeanListFactoryBean">
<property name="beanType" class="MyOptionImpl.class"/>
</bean>
</property>
</bean>
However, this all seems like a lot of effort to avoid putting #Autowired in your original class. It's not much of a violation of SoC, if it is at all - there's no compiltime dependency, and no knowledge of where the options are coming from.
Alternative to #Autowired, using a context file: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire
So you'd have:
<bean class="MenuManagementBean" autowire="byType" />
Other properties can be specified, as normal, and that would override the autowiring only for those properties.