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();
}

Reply via email to