Skip to content

Instantly share code, notes, and snippets.

@designatednerd
Last active April 9, 2018 08:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save designatednerd/153e4545af912aeed1ff to your computer and use it in GitHub Desktop.
Save designatednerd/153e4545af912aeed1ff to your computer and use it in GitHub Desktop.
package com.[my package].rule;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import timber.log.Timber;
import java.lang.annotation.*;
import java.lang.reflect.Modifier;
/**
* Cobbled together from:
* http://www.codeaffine.com/2013/11/18/a-junit-rule-to-conditionally-ignore-tests/
* https://gist.github.com/yinzara/9980184
* http://cwd.dhemery.com/2010/12/junit-rules/
* http://stackoverflow.com/questions/28145735/androidjunit4-class-org-junit-assume-assumetrue-assumptionviolatedexception/
*/
public class ConditionalIgnoreRule implements TestRule {
public interface IgnoreCondition {
boolean isSatisfied();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ConditionalIgnore {
Class<? extends IgnoreCondition> condition();
}
@Override
public Statement apply(Statement aStatement, Description aDescription) {
Statement result = aStatement;
if (hasConditionalIgnoreAnnotation(aDescription)) {
IgnoreCondition condition = getIgnoreCondition(aDescription);
if (condition.isSatisfied()) {
result = new IgnoreStatement(condition);
}
}
return result;
}
private static boolean hasConditionalIgnoreAnnotation( Description aDescription ) {
return aDescription.getAnnotation(ConditionalIgnore.class) != null;
}
private static IgnoreCondition getIgnoreCondition( Description aDescription ) {
ConditionalIgnore annotation = aDescription.getAnnotation(ConditionalIgnore.class);
return new IgnoreConditionCreator(aDescription.getTestClass(), annotation ).create();
}
private static class IgnoreConditionCreator {
private final Class<?> mTestClass;
private final Class<? extends IgnoreCondition> conditionType;
IgnoreConditionCreator(Class<?> aTestClass, ConditionalIgnore annotation) {
this.mTestClass = aTestClass;
this.conditionType = annotation.condition();
}
IgnoreCondition create() {
checkConditionType();
try {
return createCondition();
} catch( RuntimeException re ) {
throw re;
} catch( Exception e ) {
throw new RuntimeException( e );
}
}
private IgnoreCondition createCondition() throws Exception {
IgnoreCondition result;
if(isConditionTypeStandalone()) {
result = conditionType.newInstance();
} else {
result = conditionType.getDeclaredConstructor(mTestClass).newInstance(mTestClass);
}
return result;
}
private void checkConditionType() {
if(!isConditionTypeStandalone() && !isConditionTypeDeclaredInTarget()) {
String msg
= "Conditional class '%s' is a member class "
+ "but was not declared inside the test case using it.\n"
+ "Either make this class a static class, "
+ "standalone class (by declaring it in it's own file) "
+ "or move it inside the test case using it";
throw new IllegalArgumentException( String.format (msg, conditionType.getName()) );
}
}
private boolean isConditionTypeStandalone() {
return !conditionType.isMemberClass()
|| Modifier.isStatic(conditionType.getModifiers());
}
private boolean isConditionTypeDeclaredInTarget() {
return mTestClass.getClass().isAssignableFrom(conditionType.getDeclaringClass());
}
}
private static class IgnoreStatement extends Statement {
private IgnoreCondition condition;
IgnoreStatement(IgnoreCondition condition) {
this.condition = condition;
}
@Override
public void evaluate() {
Timber.d("Ignored by " + condition.getClass().getSimpleName());
//TODO: Figure out how to actually have the android tests mark this as ignored instead passing.
}
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import com.[my package].rule.ConditionalIgnoreRule;
import com.[my package].rule.MustRunOnStagingRule;
//This is an example of a test I want to run only on staging.
@RunWith(AndroidJUnit4.class)
public class CreditCardAPITests
//This must be added at the top of a test class or alternatively at the top of your base test class
//(which should not inherit from anything).
@Rule
public final ConditionalIgnoreRule mConditionalIgnore = new ConditionalIgnoreRule();
@Test
@ConditionalIgnoreRule.ConditionalIgnore(condition = MustRunOnStagingRule.class)
public void addFakeMastercard() {
//Do stuff to add a fake mastercard
}
}
package com.[my package].rule;
import com.[my package].BuildConfig;
public class MustRunOnStagingRule implements ConditionalIgnoreRule.IgnoreCondition {
@Override
public boolean isSatisfied() {
//If the build must run on staging, this should satisfy if the build_type is NOT staging.
return !BuildConfig.BUILD_TYPE.equals("staging");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment