Skip to content

Instantly share code, notes, and snippets.

@philmadden83
Last active March 25, 2021 17:48
Show Gist options
  • Save philmadden83/2726a334ce52e7181a5d to your computer and use it in GitHub Desktop.
Save philmadden83/2726a334ce52e7181a5d to your computer and use it in GitHub Desktop.
Unit test with automatic singleton mocking and wiring
package com.vivid.publik;
import com.ibatis.dao.client.DaoManager;
import com.vivid.estore.persistence.DaoConfig;
import com.vivid.estore.persistence.iface.*;
import com.vivid.estore.persistence.sqlmapdao.*;
import com.vivid.estore.util.TestFixtureFactory;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.api.mockito.PowerMockito;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.mockito.Mockito.eq;
/**
* Created by Phil Madden on 10/3/14.
*/
@SuppressStaticInitializationFor("com.vivid.estore.persistence.DaoConfig")
@PrepareForTest({ DaoConfig.class })
public abstract class BaseUnitTest {
@Mock
private static final DaoManager mockDaoManager = Mockito.mock(DaoManager.class);
private static boolean initialized = false;
protected static final TestFixtureFactory testFixtureFactory = new TestFixtureFactory();
public BaseUnitTest()
{
if(!initialized)
setup();
}
public abstract void before();
public abstract void after();
public final void setup()
{
MockitoAnnotations.initMocks(this);
mockServices();
mockDaoManagers();
before();
initialized = true;
}
public final void mockDaoManagers()
{
PowerMockito.mockStatic(DaoConfig.class);
PowerMockito.when(DaoConfig.getDaomanager()).thenReturn(mockDaoManager);
Mockito.when(mockDaoManager.getDao(eq(AccountDao.class))).thenReturn(Mockito.mock(AccountSqlMapDao.class));
Mockito.when(mockDaoManager.getDao(eq(AlertDao.class))).thenReturn(Mockito.mock(AlertSqlMapDao.class));
Mockito.when(mockDaoManager.getDao(eq(AttributeDao.class))).thenReturn(Mockito.mock(AttributeSqlMapDao.class));
Mockito.when(mockDaoManager.getDao(eq(AuditDao.class))).thenReturn(Mockito.mock(AuditSqlMapDao.class));
Mockito.when(mockDaoManager.getDao(eq(AuthorizationDao.class))).thenReturn(Mockito.mock(AuthorizationSqlMapDao.class));
Mockito.when(mockDaoManager.getDao(eq(BrokerDao.class))).thenReturn(Mockito.mock(BrokerSqlMapDao.class));
}
private void mockServices() {
if(getClass().getAnnotation(PrepareForTest.class) != null) {
PrepareForTest singletons = getClass().getAnnotation(PrepareForTest.class);
//For each class declared in the @PrepareForTest annotation
for(Class serviceClass : singletons.value()) {
try {
//Get the service's instance method
Method instanceMethod = serviceClass.getDeclaredMethod("getInstance");
PowerMockito.mockStatic(serviceClass);
//Find a instance field in the test class that references the service class
for (Field mockedServiceField : this.getClass().getDeclaredFields()) {
if (mockedServiceField.getType() == serviceClass) {
//Setup and inject the mock
Object mockedService = PowerMockito.mock(mockedServiceField.getType());
if (!mockedServiceField.isAccessible())
mockedServiceField.setAccessible(true);
try {
mockedServiceField.set(this, mockedService);
PowerMockito.when(instanceMethod.invoke(mockedService)).thenReturn(mockedService);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
break;
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
}
public final void teardown()
{
after();
}
}
A TEST
==============================================================================================================
package com.vivid.publik;
import com.vivid.estore.domain.Ticket;
import com.vivid.estore.service.EventService;
import com.vivid.estore.service.FeedService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
/**
* Created by Phil Madden on 10/3/14.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ FeedService.class, EventService.class})
public class TestEst extends BaseUnitTest {
private static FeedService mockFeedService;
private static EventService mockEventService;
@Override
public void before() {
when(mockFeedService.getItem(anyString(), anyInt())).thenReturn(testFixtureFactory.getTicket());
when(mockEventService.getCategoryContent(anyInt())).thenReturn("I'm Mocked!");
}
@Override
public void after() {
}
@Test
public void testFeedService()
{
Ticket t = mockFeedService.getItem("", 1);
assertNotNull(t);
}
@Test
public void testEventService()
{
String output = mockEventService.getCategoryContent(1);
assertTrue(output.equals("I'm Mocked!"));
}
}
@philmadden83
Copy link
Author

The "mockServices" method in the BaseUnitTest class is reflecting the test thats about to run. It automatically mocks a singleton, wires up the "when singleton.getInstance return my mock object" code and injects the mock into the test's instance field.

effectively "mockedFeedService" and "mockedEventService" will be automatically wired up to a mocked version of the service class implementation. Works pretty well.

You can still use EventService.getInstance().someMethod though. You don't have to use the instance field.

@philmadden83
Copy link
Author

It removes the boilerplate code below for each singleton you need to mock in a unit test, which could be a lot.

PowerMockito.mockStatic(Singleton.class);
PowerMockito.when(Singleton.getInstance()).thenReturn(mock(Singleton.class));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment