Created
March 1, 2016 07:33
-
-
Save mgerhardy/cbf74a4798c27df22c90 to your computer and use it in GitHub Desktop.
EasyMock + TestNG + Guice class that makes your live easier
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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