Skip to content

Instantly share code, notes, and snippets.

@mgerhardy
Created March 1, 2016 07:33
Show Gist options
  • Save mgerhardy/cbf74a4798c27df22c90 to your computer and use it in GitHub Desktop.
Save mgerhardy/cbf74a4798c27df22c90 to your computer and use it in GitHub Desktop.
EasyMock + TestNG + Guice class that makes your live easier
package com.github.mgerhardy;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.easymock.EasyMock;
import org.easymock.Mock;
import org.easymock.MockType;
import org.testng.annotations.BeforeMethod;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Modules;
/**
* This class allows each test to inject own classes and bind them to mocks. You
* can use the normal {@link @Inject} annotation and the {@link @Mock}
* annotation. Each {@link @Mock} object is automatically bind to the type of
* the mock instance. You can still override this by defining another binding in
* your {@link #configure()} method. The mocks and guice bindings are recreated
* for each test method.
*
* <p>
* <b>Dependencies:</b>
* <li>TestNG
* <li>EasyMock
* <li>Guice
*
* @author mgerhardy
*/
public class GuiceEasyMockTestNG extends AbstractModule {
private static class GuiceAndEasyMockTestGuiceModule extends AbstractModule {
private List<Wrapper<?>> mocks;
public GuiceAndEasyMockTestGuiceModule(List<Wrapper<?>> mocks) {
this.mocks = mocks;
}
@Override
protected void configure() {
binder().requireExplicitBindings();
for (Wrapper<?> object : mocks) {
object.doBind(binder());
}
}
}
private static class Wrapper<T> {
public Wrapper(T value, TypeLiteral<T> literal) {
this.value = value;
this.literal = literal;
}
final T value;
final TypeLiteral<T> literal;
public void doBind(Binder binder) {
binder.bind(literal).toInstance(value);
}
}
private final List<Wrapper<?>> mocks = new ArrayList<>();
@Override
protected void configure() {
}
/**
* Called before a test method is executed and before the mocks and guice
* bindings are handled.
*/
protected void beforeMethod() throws IOException {
}
@BeforeMethod
public void handleGuiceAndEasyMock() {
try {
beforeMethod();
createAndSetMocks(this);
final Injector injector = com.google.inject.Guice.createInjector(Modules.override(new GuiceAndEasyMockTestGuiceModule(mocks)).with(this));
injector.injectMembers(this);
} catch (final Exception ex) {
throw new RuntimeException("Could not create mocks and wire dependencies.", ex);
}
}
private Collection<Field> getAllFields(final Class<?> type) {
final Collection<Field> fields = new HashSet<>();
fields.addAll(Arrays.asList(type.getDeclaredFields()));
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
private void createAndSetMocks(final Object testInstance) throws Exception {
mocks.clear();
final Collection<Field> fields = getAllFields(testInstance.getClass());
for (final Field field : fields) {
final Mock mock = field.getAnnotation(Mock.class);
if (mock == null) {
continue;
}
final Class<?> klass = field.getType();
Object mockInstance = configure(klass, mock);
field.setAccessible(true);
field.set(testInstance, mockInstance);
}
}
private <T> T configure(Class<T> clazz, final Mock mock) {
final T mockInstance = MockType.NICE.equals(mock.type()) ? EasyMock.createNiceMock(clazz) : EasyMock.createMock(clazz);
TypeLiteral<T> typeLiteral = TypeLiteral.get(clazz);
mocks.add(new Wrapper<>(mockInstance, typeLiteral));
EasyMock.reset(mockInstance);
return mockInstance;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment