How would you mock your services which are not mock-friendly?
Let’s introduce a real case (the bad one) with some preconditions:
1. You have a service where DAOs are wired at runtime based on the some conditions.
2. DAOs lookup API is private and not exposed to the caller.
In this case you will be blocked from mocking those DAOs because of such approach.
The solution I came up with was to tweak the Spring context by unregistering the target bean (service/dao or whatever), creating the mock and registering to the context back by aliasing, to make it retrievable as regular target bean. The concept code snippet from my routine by mocking DAO’s would be:
-
protected <T extends IDao<?>> void mockDAO(Class<T> mockDaoClass) {
-
String mockedDaoClassName = mockDaoClass.getName();
-
GenericApplicationContext appContext = (GenericApplicationContext) applicationContext;
-
DefaultListableBeanFactory defaultBeanFactory = ((DefaultListableBeanFactory) appContext.getBeanFactory());
-
-
T originalDAO = (T) appContext.getBean(mockedDaoClassName);
-
T mockedDao = EasyMock.createNiceMock(mockDaoClass);
-
-
try {
-
appContext.removeBeanDefinition(mockedDaoClassName);
-
defaultBeanFactory.registerSingleton(mockedDaoClassName + DAO_ALIAS_ORIGINAL, originalDAO);
-
defaultBeanFactory.registerSingleton(mockedDaoClassName + DAO_ALIAS_MOCKED, mockedDao);
-
} catch (Exception e) {
-
fail(e.getMessage());
-
}
-
-
defaultBeanFactory.registerAlias(mockedDaoClassName + DAO_ALIAS_MOCKED, mockedDaoClassName);
-
mockedDAOGroup.add(mockedDaoClassName);
-
}
And after you finish, restore the bean alias to the original one:
-
@After
-
public void revertMockedDAOInAppContext() {
-
for (String mockedDAOClassName : mockedDAOGroup) {
-
GenericApplicationContext appContext = (GenericApplicationContext) applicationContext;
-
DefaultListableBeanFactory defaultBeanFactory = ((DefaultListableBeanFactory) appContext
-
.getBeanFactory());
-
-
defaultBeanFactory.registerAlias(mockedDAOClassName + DAO_ALIAS_ORIGINAL, mockedDAOClassName);
-
}
-
-
mockedDAOGroup.clear();
-
}
Yet another solution is to wrap the application context and override the #getBean operation. >> Check this out too <<.

