EntityManager injected by Spring but null on first use - spring

I am just working on a basic webapp that implements spring + hibernate entitymanager
I set up my dao and context exactly as described by this post:
http://blog.springsource.com/2006/08/07/using-jpa-in-spring-without-referencing-spring/
And created a test for it as shown here:
http://lstierneyltd.com/blog/development/examples/unit-testing-spring-apps-with-runwithspringjunit4classrunner-class/
For some reason when I try to access the entitymanager for creating a query, its null.
However from setting a breakpoint inside the setter method for the entitymanager I can see that Spring is injecting it correctly, and the field is being initialized.
Any clue as to why the entitymanager might be getting nullified after the setter has returned ?
Edit:
The dao code where I am setting the breakpoint:
public class ProductDaoImpl implements ProductDao {
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this. entityManager = entityManager;
}
public Collection loadProductsByCategory(String category) {
return entityManager.createQuery("from Product p where p.category = :category")
.setParameter("category", category).getResultList();
}
}

The <tx:annotation-driven/> that I presume you do have, tells Spring to put transactional advice on any class or method that has an #Transactional annotation on it.
Transactions should be defined on the Service/Business layer, hence your ProductDaoImpl is usually called from within a service, which will have #Transactional. e.g.
pubic class ProductService {
#Resource(...) // inject it the way you like e.g. #Autowired / Setter / Constructor injection, etc..
ProductDao yourProductDao;
#Transactional
public List<Product> findCarProducts {
yourProductDao.loadProductsByCategory( "car" );
}
}
(alternatively, you can use an XML based transaction configuration)
Now the actual call to your DAO will be within a transaction => which is very important for entityManager / Hibernate Session. Otherwise you'll see all the usual errors: e.g. entityManager is null, entityManager is closed, etc..
In case you'd like to test a DAO in solo, you have to make sure that your test case is wrapped within a transaction via #TransactionConfiguration. For example, if your transaction manager bean is defined as:
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Your DAO test would include this bean name:
#ContextConfiguration
#TransactionConfiguration(transactionManager="txManager", defaultRollback=false)
public class ProductDaoTransactionalTests {
// your use cases here..
}
You can read more about transactional tests in Spring Documentation

Related

No Session Hibernate in #PostConstruct

MyDao class have the methods to do whole persistence tasks through Hibernate SessionFactory, it works fine.
I inject MyDao in MyService as can see above, but when #PostConstruct init() method is called after injected MyDao (debugging I can see MyDao well injected) get the next Hibernate exception:
org.hibernate.HibernateException: No Session found for current thread
My service implementation.
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#PostConstruct
public void init() {
this.cacheList = new CacheList();
this.cacheList.reloadCache(this.myDao.getAllFromServer());
}
...
}
WAY TO SOLVE
As #Yogi recommended above to me, I have used TransactionTemplate to get one valid/active transaction session, in this case I have implemented throught constructor and works fine for me.
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
...
}
I don't think there is any transaction allowed on #PostConstruct level so #Transactional won't do much here unless mode is set to aspectj in <tx:annotation-driven mode="aspectj" />.
As per this discussion you can use TransactionTemplate to start manual transaction inside init() to bind session but if you intend to strictly adhere to declarative transaction you need to use ApplicationListener to register event and user ContextRefreshedEvent to initiate transaction.
Make sure you are running under transaction. I can see the transaction annotation but looks like you missed to activate the transaction management using annotation through the use of using <tx:annotation-driven/> tag in spring context.
This happens because MyServiceImpl.init() is called by Spring after MyServiceImpl related bean construction and #Transaction annotation is not used to manage session lifecycle.
A solution might be consider Spring AOP around methods that use the cache instead of #PostConstruct

What are advantages of spring DAOSupport

I read about Spring framework's DAOSupport classes. But I could not understand the advantages of these DAOSuport classes. In DAOSupport classes we call getXXXTemplate() method to get the specific template object and then use it further for DB access.
Even without extending DAOSupport we can inject XXXTemplate in our class.
Rest of this things will remain same.
Then what is advantage of extending DAOSupport class?
EDIT:- Adding example
Class extends spring's SimpleJdbcDaoSupport
public class JdbcDao extends SimpleJdbcDaoSupport {
public int create(Bb obj) {
getSimpleJdbcTemplate().update("insert into ..... ") //insert query
}
Bean of this class can be defined as :-
<bean id="jdbcDao" class="example.dao.support.JdbcDao">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
We can create a custom class without extending SimpleJdbcDaoSupport which will have property of type JdbcTemplate
public class MyDAO {
public myJdbcTemplate; // ant its getter and setter
public int create(Bb obj) {
getMyJdbcTemplate().update("insert into ..... ") //insert query
}
It's bean wil be defined as :-
<bean id="jdbcDao" class="MyDAO">
<property name="myJdbcTemplate"><ref local="jdbcTemplateBean"/></property>
</bean>
As you can see both classes do same thing. While extending SimpleJdbcDaoSupport we are injecting DataSource and without it we are injecting directly jdbcTemplate bean. That's it. No more difference.
So I do not see any much advantage with this much use of DAOSupport classes. Any additional functionality given by DAOSupport classes ?
When you use HibernateDAOSupport you can see the difference.
1. Config the transaction to optimize the performance of the application on the applicationContext :
select : read only
create/update : read and write.
You use one session only(with getHibernateTemplate() and the sessionFactory)
When we update some data on the database we do only merge the modifications whith the method impleted on HibernateDAOSupport.
There are many method already implemented on the DAOSupport and we can use this to our need.

"HibernateException: No Session found for current thread" when calling DAO from Transactional service method

I have a service bean that loads objects from the database after instantiation into an object cache. If I label the service method that calls my DAO object method as #Transactional, then I get the "HibernateException: No Session found for current thread" error. However, if I label the DAO class as #Transactional, I get no such error and it works fine.
The problem is that I can't then make multiple DAO calls from the same method in the service object and have it be one transaction. Are there any thoughts on what might cause this?
I am using Spring 3.1 and Hibernate 4.
DAO Example:
#Repository
public class HibernateObjectDao implements ObjectDao {
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List<Object> getObjects() {
return sessionFactory.getCurrentSession()
.createQuery("from Object").list();
}
}
Service Bean example:
#Service
public class MyServiceBean implements AbstractMyServiceBean
{
#Resource
private ObjectDao objectDao;
private HashMap<String,Object> objectCache;
public MyServiceBean() {
this.objectCache = new HashMap<String,Object>();
}
#Autowired
public void setObjectDao(ObjectDao objectDao) {
this.objectDao = objectDao;
}
#Transactional
public void initialize() {
loadObjectCache();
}
public void loadObjectCache() {
objectCache.put("stuff",this.objectDao.getObjects())
}
}
ApplicationContext.xml excerpt:
<bean id="objectDao" class="com.example.persistence.HibernateObjectDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="myServiceBean"
class="com.example.service.MyServiceBean"
init-method="initialize">
<property name="objectDao" ref="objectDao" />
</bean>
Methods are transactional when they're called from the outside of the bean, using an injected instance of the bean, which is in reality a transactional proxy around the actual bean instance.
Spring calls the initialize method directly on the bean instance, not on the transactional proxy, so the methods are not called in a transaction.
Put an initialize method in another bean, which will use an injected MyServiceBean and call its initialize() method.
The problem is that there is no transactional proxy around the bean when Spring calls initialize. This is on purpose, as the philosophy is that the bean is not ready for use until it is init'd.
Some solutions:
In this special case of init-time data processing, do manual transaction handling via TransactionTemplate or session.beginTransaction(). If you use JPA/Hibernate, use code like this to add the EntityManager to the Transaction Synchronizer:
EntityManager em = entityManagerFactory.createEntityManager();
TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(em));
Create another bean for all initializing type events in your application and let that call other beans. By that time, all the other beans will be ready and Spring will put a transactional proxy around them. Note: do not call the method set as an init-method from this bean as this way that particular bean will be initialized twice, which is not always healthy :) Create another method for this purpose.
Use an ApplicationListener. With this one, you can register a callback and handle the ContextRefreshedEvent as a sign that the context initialization is done.

Spring3 's #Transactional #Scheduled not committed to DB?

This is my 1st time trying Spring3's #Scheduled , but found I cannot commit to DB. This is my code :
#Service
public class ServiceImpl implements Service , Serializable
{
#Inject
private Dao dao;
#Override
#Scheduled(cron="0 0 * * * ?")
#Transactional(rollbackFor=Exception.class)
public void hourly()
{
// get xxx from dao , modify it
dao.update(xxx);
}
}
I think it should work , I can see it starts-up hourly and load xxx from DB , but data is not committed to DB.
There's been tx:annotation-driven in spring's xml :
<bean id="entityManagerFactoryApp" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myapp"/>
</bean>
<bean id="transactionManagerApp" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryApp" />
</bean>
<tx:annotation-driven transaction-manager="transactionManagerApp" />
Can somebody tell me what I missed here ?
I have one 'dirty' solution :
#Service
public class ServiceImpl implements Service , Serializable
{
#Inject
private Dao dao;
#Inject
#Qualifier("transactionManagerApp")
private PlatformTransactionManager txMgrApp;
#Override
#Scheduled(cron="0 0 * * * ?")
#Transactional(rollbackFor=Exception.class)
public void hourly()
{
final TransactionTemplate txTemplateApp = new TransactionTemplate(txMgrApp);
txTemplateApp.execute(new TransactionCallbackWithoutResult()
{
#Override
protected void doInTransactionWithoutResult(TransactionStatus status)
{
//get xxx from dao
dao.update(xxx);
}
});
}
}
It works fine here , but it is so redundant , making the code harder to read.
I wonder why TransactionManager is not injected (and opened) in the previous code snippets?
Thanks a lot !
You probably have figured this out or moved on (I hope so), but for the benefit of others:
The #Transactional annotation tells Spring to wrap your original ServiceImpl bean with a dynamic proxy that also implements 'Service' (by default Spring proxies the interface, not the implementation). This proxy will transparently handle the creation and commit/rollback of the transaction when you call hourly() on the proxy. However, if you call hourly() directly on your implementation (which is what is happening above), the proxy is bypassed, so there is no transaction.
http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/
The solution is to either
Demarcate the transaction programmatically as you are doing in your 'dirty' solution (you don't need the annotations is this case).
Make sure that your #Scheduled method makes its call to dao.update(xxx); via the Service interface, not directly on your implementation (thereby going through the proxy). Basically you need to move the #Scheduled method to another bean.
I hope that is clear enough!
When you use annotation-driven support, it only works on classes created within that context. My bet is that ServiceImpl is not created in the same context as your transaction manager (either directly or by annotation scanning).
I had the same problem and after spending time on it, I realized that I got an exception after the dao.update() call in some unrelated code that didn't check null value - so it simply broke the transaction.
There was no stackTrace printing because it has been treated well by spring (some catch block).
I spent a while on that.
So - just verify that your transaction method completes till its end.
Hope it will help someone.
Yosi Lev

Injecting Mockito mocks into a Spring bean

I would like to inject a Mockito mock object into a Spring (3+) bean for the purposes of unit testing with JUnit. My bean dependencies are currently injected by using the #Autowired annotation on private member fields.
I have considered using ReflectionTestUtils.setField but the bean instance that I wish to inject is actually a proxy and hence does not declare the private member fields of the target class. I do not wish to create a public setter to the dependency as I will then be modifying my interface purely for the purposes of testing.
I have followed some advice given by the Spring community but the mock does not get created and the auto-wiring fails:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
The error I currently encounter is as follows:
...
Caused by: org...NoSuchBeanDefinitionException:
No matching bean of type [com.package.Dao] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {
#org...Autowired(required=true),
#org...Qualifier(value=dao)
}
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)
If I set the constructor-arg value to something invalid no error occurs when starting the application context.
The best way is:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
Update
In the context file this mock must be listed before any autowired field depending on it is declared.
#InjectMocks
private MyTestObject testObject;
#Mock
private MyDependentObject mockedObject;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
This will inject any mocked objects into the test class. In this case it will inject mockedObject into the testObject. This was mentioned above but here is the code.
I have a very simple solution using Spring Java Config and Mockito:
#Configuration
public class TestConfig {
#Mock BeanA beanA;
#Mock BeanB beanB;
public TestConfig() {
MockitoAnnotations.initMocks(this); //This is a key
}
//You basically generate getters and add #Bean annotation everywhere
#Bean
public BeanA getBeanA() {
return beanA;
}
#Bean
public BeanB getBeanB() {
return beanB;
}
}
Given:
#Service
public class MyService {
#Autowired
private MyDAO myDAO;
// etc
}
You can have the class that is being tested loaded via autowiring, mock the dependency with Mockito, and then use Spring's ReflectionTestUtils to inject the mock into the class being tested.
#ContextConfiguration(classes = { MvcConfiguration.class })
#RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
#Autowired
private MyService myService;
private MyDAO myDAOMock;
#Before
public void before() {
myDAOMock = Mockito.mock(MyDAO.class);
ReflectionTestUtils.setField(myService, "myDAO", myDAOMock);
}
// etc
}
Please note that before Spring 4.3.1, this method won't work with services behind a proxy (annotated with #Transactional, or Cacheable, for example). This has been fixed by SPR-14050.
For earlier versions, a solution is to unwrap the proxy, as described there: Transactional annotation avoids services being mocked (which is what ReflectionTestUtils.setField does by default now)
If you're using Spring Boot 1.4, it has an awesome way of doing this. Just use new brand #SpringBootTest on your class and #MockBean on the field and Spring Boot will create a mock of this type and it will inject it into the context (instead of injecting the original one):
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTests {
#MockBean
private RemoteService remoteService;
#Autowired
private Reverser reverser;
#Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}
}
On the other hand, if you're not using Spring Boot or are you using a previous version, you'll have to do a bit more work:
Create a #Configuration bean that injects your mocks into Spring context:
#Configuration
#Profile("useMocks")
public class MockConfigurer {
#Bean
#Primary
public MyBean myBeanSpy() {
return mock(MyBean.class);
}
}
Using #Primary annotation you're telling spring that this bean has priority if no qualifier are specified.
Make sure you annotate the class with #Profile("useMocks") in order to control which classes will use the mock and which ones will use the real bean.
Finally, in your test, activate userMocks profile:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Application.class})
#WebIntegrationTest
#ActiveProfiles(profiles={"useMocks"})
public class YourIntegrationTestIT {
#Inject
private MyBean myBean; //It will be the mock!
#Test
public void test() {
....
}
}
If you don't want to use the mock but the real bean, just don't activate useMocks profile:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Application.class})
#WebIntegrationTest
public class AnotherIntegrationTestIT {
#Inject
private MyBean myBean; //It will be the real implementation!
#Test
public void test() {
....
}
}
Since 1.8.3 Mockito has #InjectMocks - this is incredibly useful. My JUnit tests are #RunWith the MockitoJUnitRunner and I build #Mock objects that satisfy all the dependencies for the class being tested, which are all injected when the private member is annotated with #InjectMocks.
I #RunWith the SpringJUnit4Runner for integration tests only now.
I will note that it does not seem to be able to inject List<T> in the same manner as Spring. It looks only for a Mock object that satisfies the List, and will not inject a list of Mock objects. The workaround for me was to use a #Spy against a manually instantiated list, and manually .add the mock object(s) to that list for unit testing. Maybe that was intentional, because it certainly forced me to pay close attention to what was being mocked together.
Update: There are now better, cleaner solutions to this problem. Please consider the other answers first.
I eventually found an answer to this by ronen on his blog. The problem I was having is due to the method Mockito.mock(Class c) declaring a return type of Object. Consequently Spring is unable to infer the bean type from the factory method return type.
Ronen's solution is to create a FactoryBean implementation that returns mocks. The FactoryBean interface allows Spring to query the type of objects created by the factory bean.
My mocked bean definition now looks like:
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
<property name="type" value="com.package.Dao" />
</bean>
As of Spring 3.2, this is no longer an issue. Spring now supports Autowiring of the results of generic factory methods. See the section entitled "Generic Factory Methods" in this blog post: http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/.
The key point is:
In Spring 3.2, generic return types for factory methods are now
properly inferred, and autowiring by type for mocks should work as
expected. As a result, custom work-arounds such as a
MockitoFactoryBean, EasyMockFactoryBean, or Springockito are likely no
longer necessary.
Which means this should work out of the box:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
If you're using spring >= 3.0, try using Springs #Configuration annotation to define part of the application context
#Configuration
#ImportResource("com/blah/blurk/rest-of-config.xml")
public class DaoTestConfiguration {
#Bean
public ApplicationService applicationService() {
return mock(ApplicationService.class);
}
}
If you don't want to use the #ImportResource, it can be done the other way around too:
<beans>
<!-- rest of your config -->
<!-- the container recognize this as a Configuration and adds it's beans
to the container -->
<bean class="com.package.DaoTestConfiguration"/>
</beans>
For more information, have a look at spring-framework-reference : Java-based container configuration
Below code works with autowiring - it is not the shortest version but useful when it should work only with standard spring/mockito jars.
<bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"> <bean class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.package.Dao" /> </bean> </property>
<property name="proxyInterfaces"> <value>com.package.Dao</value> </property>
</bean>
Perhaps not the perfect solution, but I tend not to use spring to do DI for unit tests. the dependencies for a single bean (the class under test) usually aren't overly complex so I just do the injection directly in the test code.
I can do the following using Mockito:
<bean id="stateMachine" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.abcd.StateMachine"/>
</bean>
Posting a few examples based on the above approaches
With Spring:
#ContextConfiguration(locations = { "classpath:context.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class TestServiceTest {
#InjectMocks
private TestService testService;
#Mock
private TestService2 testService2;
}
Without Spring:
#RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {
#InjectMocks
private TestService testService = new TestServiceImpl();
#Mock
private TestService2 testService2;
}
Update - new answer here: https://stackoverflow.com/a/19454282/411229. This answer only applies to those on Spring versions before 3.2.
I've looked for a while for a more definitive solution to this. This blog post seems to cover all my needs and doesn't rely on ordering of bean declarations. All credit to Mattias Severson. http://www.jayway.com/2011/11/30/spring-integration-tests-part-i-creating-mock-objects/
Basically, implement a FactoryBean
package com.jayway.springmock;
import org.mockito.Mockito;
import org.springframework.beans.factory.FactoryBean;
/**
* A {#link FactoryBean} for creating mocked beans based on Mockito so that they
* can be {#link #Autowired} into Spring test configurations.
*
* #author Mattias Severson, Jayway
*
* #see FactoryBean
* #see org.mockito.Mockito
*/
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private Class<T> classToBeMocked;
/**
* Creates a Mockito mock instance of the provided class.
* #param classToBeMocked The class to be mocked.
*/
public MockitoFactoryBean(Class<T> classToBeMocked) {
this.classToBeMocked = classToBeMocked;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(classToBeMocked);
}
#Override
public Class<?> getObjectType() {
return classToBeMocked;
}
#Override
public boolean isSingleton() {
return true;
}
}
Next update your spring config with the following:
<beans...>
<context:component-scan base-package="com.jayway.example"/>
<bean id="someDependencyMock" class="com.jayway.springmock.MockitoFactoryBean">
<constructor-arg name="classToBeMocked" value="com.jayway.example.SomeDependency" />
</bean>
</beans>
I use a combination of the approach used in answer by Markus T and a simple helper implementation of ImportBeanDefinitionRegistrar that looks for a custom annotation (#MockedBeans) in which one can specify which classes are to be mocked. I believe that this approach results in a concise unit test with some of the boilerplate code related to mocking removed.
Here's how a sample unit test looks with that approach:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ExampleServiceIntegrationTest {
//our service under test, with mocked dependencies injected
#Autowired
ExampleService exampleService;
//we can autowire mocked beans if we need to used them in tests
#Autowired
DependencyBeanA dependencyBeanA;
#Test
public void testSomeMethod() {
...
exampleService.someMethod();
...
verify(dependencyBeanA, times(1)).someDependencyMethod();
}
/**
* Inner class configuration object for this test. Spring will read it thanks to
* #ContextConfiguration(loader=AnnotationConfigContextLoader.class) annotation on the test class.
*/
#Configuration
#Import(TestAppConfig.class) //TestAppConfig may contain some common integration testing configuration
#MockedBeans({DependencyBeanA.class, DependencyBeanB.class, AnotherDependency.class}) //Beans to be mocked
static class ContextConfiguration {
#Bean
public ExampleService exampleService() {
return new ExampleService(); //our service under test
}
}
}
To make this happen you need to define two simple helper classes - custom annotation (#MockedBeans) and a custom
ImportBeanDefinitionRegistrar implementation. #MockedBeans annotation definition needs to be annotated with #Import(CustomImportBeanDefinitionRegistrar.class) and the ImportBeanDefinitionRgistrar needs to add mocked beans definitions to the configuration in it's registerBeanDefinitions method.
If you like the approach you can find sample implementations on my blogpost.
Looking at Springockito pace of development and number of open issues, I would be little bit worried to introduce it into my test suite stack nowadays. Fact that last release was done before Spring 4 release brings up questions like "Is it possible to easily integrate it with Spring 4?". I don't know, because I didn't try it. I prefer pure Spring approach if I need to mock Spring bean in integration test.
There is an option to fake Spring bean with just plain Spring features. You need to use #Primary, #Profile and #ActiveProfiles annotations for it. I wrote a blog post on the topic.
I found a similar answer as teabot to create a MockFactory that provides the mocks. I used the following example to create the mock factory (since the link to narkisr are dead):
http://hg.randompage.org/java/src/407e78aa08a0/projects/bookmarking/backend/spring/src/test/java/org/randompage/bookmarking/backend/testUtils/MocksFactory.java
<bean id="someFacade" class="nl.package.test.MockFactory">
<property name="type" value="nl.package.someFacade"/>
</bean>
This also helps to prevent that Spring wants to resolve the injections from the mocked bean.
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
<property name="type" value="com.package.Dao" />
</bean>
this ^ works perfectly well if declared first/early in the XML file. Mockito 1.9.0/Spring 3.0.5
I developed a solution based on the proposal of Kresimir Nesek. I added a new annotation #EnableMockedBean in order to make the code a bit cleaner and modular.
#EnableMockedBean
#SpringBootApplication
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes=MockedBeanTest.class)
public class MockedBeanTest {
#MockedBean
private HelloWorldService helloWorldService;
#Autowired
private MiddleComponent middleComponent;
#Test
public void helloWorldIsCalledOnlyOnce() {
middleComponent.getHelloMessage();
// THEN HelloWorldService is called only once
verify(helloWorldService, times(1)).getHelloMessage();
}
}
I have written a post explaining it.
I would suggest to migrate your project to Spring Boot 1.4. After that you can use new annotation #MockBean to fake your com.package.Dao
Today I found out that a spring context where I declared a before the Mockito beans, was failing to load.
After moving the AFTER the mocks, the app context was loaded successfully.
Take care :)
For the record, all my tests correctly work by just making the fixture lazy-initialized, e.g.:
<bean id="fixture"
class="it.tidalwave.northernwind.rca.embeddedserver.impl.DefaultEmbeddedServer"
lazy-init="true" /> <!-- To solve Mockito + Spring problems -->
<bean class="it.tidalwave.messagebus.aspect.spring.MessageBusAdapterFactory" />
<bean id="applicationMessageBus"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="it.tidalwave.messagebus.MessageBus" />
</bean>
<bean class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="javax.servlet.ServletContext" />
</bean>
I suppose the rationale is the one Mattias explains here (at the bottom of the post), that a workaround is changing the order the beans are declared - lazy initialization is "sort of" having the fixture declared at the end.
If you're using spring boot 2.2+, you can use #MockInBean as an alternative to #MockBean and keep your Spring context clean:
#SpringBootTest
public class MyServiceTest {
#MockInBean(MyService.class)
  private ServiceToMock serviceToMock;
    #Autowired
    private MyService myService;
    #Test
    public void test() {
        Mockito.when(serviceToMock.returnSomething()).thenReturn(new Object());
        myService.doSomething();
    }
}
disclaimer: I created this library to avoid Spring Context re-creation caused by #MockBean/#SpringBean that leads to slow build test phases (see Using #MockBean in tests forces reloading of Application Context or the problem with #MockBean)

Resources