Android

Android unit test config conditi

2018-08-30  本文已影响2人  JaedenKil
testA=Y
testB=N
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}


task copyConfig(type: Copy) {
    description = "Copy the config file from the project root folder to 'app/src/main/assets/', if the config file exists in root folder."
    if (file("config.ini").exists()) {
        println "The 'config.ini' exists in root folder, copy to assert now."
        from "$rootDir/config.ini"
        into "app/src/main/assets/"
    } else {
        println "The 'config.ini' does not exist in root folder. Will run default tests."
    }
}
In this case, a gradle task will run first ./gradlew copyConfig, then ./gradlew --build-cache connectedDebugAndroid.
package com.XXX.YYY;

import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Modifier;

import org.junit.Assume;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;

public class ConditionalIgnoreRule implements MethodRule {

    public interface IgnoreCondition {
        boolean isSatisfied() throws IOException;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface ConditionalIgnore {
        Class<? extends IgnoreCondition> condition();
    }

    @Override
    public Statement apply( Statement base, FrameworkMethod method, Object target ) {
        Statement result = base;
        if( hasConditionalIgnoreAnnotation( method ) ) {
            IgnoreCondition condition = getIgnoreContition( target, method );
            try {
                if( condition.isSatisfied() ) {
                    result = new IgnoreStatement( condition );
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    private static boolean hasConditionalIgnoreAnnotation( FrameworkMethod method ) {
        return method.getAnnotation( ConditionalIgnore.class ) != null;
    }

    private static IgnoreCondition getIgnoreContition( Object target, FrameworkMethod method ) {
        ConditionalIgnore annotation = method.getAnnotation( ConditionalIgnore.class );
        return new IgnoreConditionCreator( target, annotation ).create();
    }

    private static class IgnoreConditionCreator {
        private final Object target;
        private final Class<? extends IgnoreCondition> conditionType;

        IgnoreConditionCreator( Object target, ConditionalIgnore annotation ) {
            this.target = target;
            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( target.getClass() ).newInstance( target );
            }
            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 target.getClass().isAssignableFrom( conditionType.getDeclaringClass() );
        }
    }

    private static class IgnoreStatement extends Statement {
        private final IgnoreCondition condition;

        IgnoreStatement( IgnoreCondition condition ) {
            this.condition = condition;
        }

        @Override
        public void evaluate() {
            Assume.assumeTrue( "Ignored by " + condition.getClass().getSimpleName(), false );
        }
    }

}
    @Rule
    public ConditionalIgnoreRule rule = new ConditionalIgnoreRule();
public String readFromConfig(Context ctx, String configFileName) {
        InputStream in = null;
        try {
            in = ctx.getAssets().open(configFileName);
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line).append(System.getProperty("line.separator"));
            }
            in.close();
            reader.close();
            String config = builder.toString();
            Log.v(LOG_TAG, "readFromConfig: The config content is:");
            Log.v(LOG_TAG, "*********************************");
            Log.v(LOG_TAG, config);
            Log.v(LOG_TAG, "*********************************");
            return config;
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(LOG_TAG, "readFromConfig: The 'config.ini' file is missing in the assets folder.");
            Log.d(LOG_TAG, "readFromConfig: Will ignore the config and run all tests.");
            return null;
        }
    public boolean willRun(Context ctx, String configFileName, String caseName) throws IOException {
        String config = readFromConfig(ctx, configFileName);
        return config == null || config.contains(caseName);
    }

public class IgnoreTestA implements ConditionalIgnoreRule.IgnoreCondition {

        @Override
        public boolean isSatisfied() {
            try {
                //If return true, will skip the test; Else will run it.
                return willRun(ctx, CONFIG_FILE_NAME, "testA=Y");
            } catch (IOException e) {
                e.printStackTrace();
            }
            //If config file not found, consider default as "Run all".
            return false;
        }
    }
@ConditionalIgnoreRule.ConditionalIgnore( condition = IgnoreTestA.class )
@Test
public void testA() {
     ...
}

Finally, we can decide a test will run or skip according to the config file.

And alternatively, if we just want to conditionally skip a test, but do not care whether the @Before and @After will run accordingly or not, we can just do this:

@Test
public void testA() {
    Assume.assumeFalse(willRun(ctx, CONFIG_FILE_NAME, "testA=Y"));
}
上一篇 下一篇

猜你喜欢

热点阅读