package org.togglz.junit.vary; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import org.junit.runner.Runner; import org.junit.runners.Suite; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.TestClass; import org.togglz.core.Feature; /** * <p> * This class is custom JUnit runner that allows to run tests against different feature combinations. A usecase for this runner * would be for example to test feature toggles that enable caching behavior. The runner can be configured to run the tests two * times. Once with the flag enabled and once with the flag being disabled. * </p> * * <p> * Tests executed with this runner must implement a public static method annotated with {@link Variations}. This method must * return a {@link VariationSet} set specifies which features should be varied. * </p> * * <p> * Usage example: * </p> * * <pre> * @RunWith(FeatureVariations.class) * public class FeatureVariationsTest { * * @Variations * public static VariationSet<MyFeatures> getPermutations() { * return VariationSetBuilder.create(MyFeatures.class) * .enable(MyFeatures.FEATURE_ONE) * .vary(MyFeatures.FEATURE_TWO); * } * * @Test * public void test() { * // do the tests * } * * } * </pre> * * <p> * In this example the test is executed two times. Once with <code>FEATURE_TWO</code> being active and once with * <code>FEATURE_TWO</code> being inactive. In both runs <code>FEATURE_ONE</code> is enabled. * * @author Christian Kaltepoth */ public class FeatureVariations extends Suite { protected List<Runner> runners = new ArrayList<Runner>(); public FeatureVariations(Class<?> clazz) throws InitializationError { super(clazz, Collections.<Runner> emptyList()); TestClass testClass = new TestClass(clazz); VariationSetBuilder<? extends Feature> permutation = getPermutationFromMethod(testClass); if (permutation == null) { throw new IllegalStateException("You have to place a @" + Variations.class.getSimpleName() + " annotation one the class: " + clazz.getName()); } for (Set<? extends Feature> activeFeatures : permutation.getVariants()) { runners.add(new VariationRunner(clazz, permutation.getFeatureClass(), activeFeatures)); } } private VariationSetBuilder<? extends Feature> getPermutationFromMethod(TestClass testClass) { List<FrameworkMethod> methods = testClass.getAnnotatedMethods(Variations.class); for (FrameworkMethod method : methods) { int modifiers = method.getMethod().getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) { try { return (VariationSetBuilder) method.invokeExplosively(null); } catch (Throwable e) { throw new IllegalStateException(e); } } } throw new IllegalStateException("Could not find public static method annotated with @" + Variations.class.getSimpleName() + " on class: " + testClass.getName()); } @Override protected List<Runner> getChildren() { return runners; } }