Hi Antoine
Thank you very much for your code. I am using it in my integration tests. I
ran into the problem, that It did only work with the test class annotated
with @WithModules.
Because I wanted to be able to place it also in the subclasses or
interfaces of the test class, I modified your code to allow that. Although
I am not sure wether it makes sense in the interface...
Here is the modified code....
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To view this discussion on the web visit
https://groups.google.com/d/msg/google-guice/-/3QNZ8kUDPXUJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* <p>
* This <code>GuiceTestRunner</code> class is used for running tests that has dependencies that should be loaded by Guice.
* </p>
* <p>
* The test class should also define the <code>@WithModules</code> annotation.
* </p>
*
*/
public class GuiceTestRunner extends BlockJUnit4ClassRunner {
private Injector injector;
public GuiceTestRunner(Class<?> clazz) throws InitializationError {
super(clazz);
}
/**
* Create the Guice injector.
*
* @return New injector.
*/
protected Injector createInjector() throws Exception {
List<Module> modules = new ArrayList<Module>();
StringBuilder builder = new StringBuilder();
// Check the @WithModules annotation
// register class and subclasses
for (Class<?> c = this.getTestClass().getJavaClass(); c != Object.class; c = c.getSuperclass()) {
modules.addAll(getModules(c));
builder.append(c.getName() + ", ");
}
// register interfaces
for (Class<?> c : this.getTestClass().getJavaClass().getInterfaces()) {
modules.addAll(getModules(c));
builder.append(c.getName() + ", ");
}
if (modules.size() < 1) {
throw new InitializationError(" At leas one of the classes: " + builder.toString() + " should have the @WithModules annotation");
}
// Return the injector
return Guice.createInjector(modules);
}
protected List<Module> getModules(Class<?> c) throws Exception {
List<Module> modules = new ArrayList<Module>();
WithModules wm = c.getAnnotation(WithModules.class);
if (wm == null) {
return modules;
}
Class<? extends Module>[] moduleClasses = wm.values();
// Instantiate the modules
for (int i = 0; i < moduleClasses.length; i++) {
if (moduleClasses[i] == null) {
throw new Exception("A module class within the @WithModules annotation cannot be null.");
}
try {
modules.add(moduleClasses[i].newInstance());
} catch (Exception e) {
throw new Exception("The module " + moduleClasses[i] + " is required by the test and cannot be instantiated.", e);
}
}
return modules;
}
@Override protected Object createTest() throws Exception {
return ensureInjector().getInstance(this.getTestClass().getJavaClass());
}
protected final Injector ensureInjector() throws Exception {
if (this.injector == null) {
this.injector = createInjector();
}
return this.injector;
}
@Override protected void validateConstructor(List<Throwable> errors) {
// Get the constructors
Constructor<?>[] constructors = this.getTestClass().getJavaClass().getDeclaredConstructors();
if (constructors.length == 0) {
return;
}
// Search for a valid one
for (Constructor<?> c : constructors) {
// Modifiers: 0: package, 1: public, 2: private, 4: protected
boolean hasAccess = (c.getModifiers() != 2);
boolean noArgs = (c.getParameterTypes().length == 0);
boolean hasInject = (c.getAnnotation(Inject.class) != null);
if (hasAccess && (noArgs || hasInject)) {
return;
}
}
errors.add(new Exception("The class should have a constructor with the @Inject annotation or one with no argument."));
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.google.inject.Module;
/**
* <p>
* This <code>@WithModule </code>annotation is used when writing test that requires Guice. It indicates which modules should be loaded.
* </p>
*
* Annotate the test class, baseclass or interface with this annotation.<br>
* e.g.<code>@WithModules({DummyModule.class, DbModule.class} ) </code><br>
*
* @see com.google.inject.Module
*
*/
@Target({ ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface WithModules {
/**
* Array of all the modules' classes to load for configuring the Guice injector.
*
* @return Modules' classes to load.
*/
public Class<? extends Module>[] values();
}