首页 文章

如何检测Android应用程序是否正在使用Espresso运行UI测试

提问于
浏览
16

我正在为Android编写一些Espresso测试 . 我正在运行以下问题:

为了使某个测试用例正常运行,我需要在应用程序中禁用某些功能 . 因此,在我的应用程序中,我需要检测我是否正在运行Espresso测试,以便我可以禁用它 . 但是,我不想使用 BuildConfig.DEBUG ,因为我不希望在调试版本中禁用这些功能 . 此外,我想避免创建一个新的buildConfig,以避免创建太多的构建变体(我们已经定义了很多风格) .

我一直在寻找一种方法来定义buildConfigField以进行测试,但我在Google上找不到任何引用 .

7 回答

  • 24

    结合CommonsWare的答案 . 这是我的解决方案:

    我定义了一个 AtomicBoolean 变量和一个函数来检查它是否正在运行测试:

    private AtomicBoolean isRunningTest;
    
    public synchronized boolean isRunningTest () {
        if (null == isRunningTest) {
            boolean istest;
    
            try {
                Class.forName ("myApp.package.name.test.class.name");
                istest = true;
            } catch (ClassNotFoundException e) {
                istest = false;
            }
    
            isRunningTest = new AtomicBoolean (istest);
        }
    
        return isRunningTest.get ();
    }
    

    这样可以避免每次需要检查值时执行try-catch检查,并且只在第一次调用此函数时才运行检查 .

  • 2

    结合Commonsware评论Comtaler的解决方案是使用Espresso框架为任何测试类做到这一点的方法 .

    public static synchronized boolean isRunningTest () {
            if (null == isRunningTest) {
                boolean istest;
    
                try {
                    Class.forName ("android.support.test.espresso.Espresso");
                    istest = true;
                } catch (ClassNotFoundException e) {
                    istest = false;
                }
    
                isRunningTest = new AtomicBoolean (istest);
            }
    
            return isRunningTest.get();
        }
    
  • 3

    基于上面的答案,以下Kotlin代码是等效的:

    val isRunningTest : Boolean by lazy {
        try {
            Class.forName("android.support.test.espresso.Espresso")
            true
        } catch (e: ClassNotFoundException) {
            false
        }
    }
    

    然后,您可以检查属性的值:

    if (isRunningTest) {
      // Espresso only code
    }
    
  • 2

    BuildConfig 班的旗帜怎么样?

    android {
        defaultConfig {
            // No automatic import :(
            buildConfigField "java.util.concurrent.atomic.AtomicBoolean", "IS_TESTING", "new java.util.concurrent.atomic.AtomicBoolean(false)"
        }
    }
    

    在测试类中的某处添加它 .

    static {
        BuildConfig.IS_TESTING.set(true);
    }
    
  • 11

    您可以使用SharedPreferences .

    设置调试模式:

    boolean isDebug = true;
    
    SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putInt("DEBUG_MODE", isDebug);
    editor.commit();
    

    检查调试模式是否:

    SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
    boolean isDebug = sharedPref.getBoolean("DEBUG_MODE", false);
    
    if(isDebug){
        //Activate debug features
    }else{
        //Disable debug features
    }
    
  • 29

    我将创建两个文件,如下所示

    src / main /.../ Injection.java src / androidTest /.../ Injection.java

    在Injection.java中,我将使用不同的实现,或者仅使用静态变量 .

    由于androidTest是源集,而不是构建类型的一部分,我认为你想做的事情很难 .

  • 1

    我不喜欢使用在android上慢的反射 . 我们大多数人都设置了dagger2用于依赖注入 . 我有一个测试组件用于测试 . 以下是您可以获得应用程序模式(测试或正常)的简短方法:

    创建一个枚举:

    public enum ApplicationMode {
        NORMAL,TESTING;
    }
    

    和一个普通的AppModule:

    @Module
    public class AppModule {
    
        @Provides
        public ApplicationMode provideApplicationMode(){
            return ApplicationMode.NORMAL;
        }
    }
    

    像我一样创建一个测试运行器:

    public class PomeloTestRunner extends AndroidJUnitRunner {
    
        @Override
        public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
                return super.newApplication(cl, MyTestApplication.class.getName(), context);
        }
    }
    

    别忘了像这样在gradle中声明它:

    defaultConfig {
    testInstrumentationRunner "com.mobile.pomelo.base.PomeloTestRunner"
    }
    

    现在使用覆盖方法创建AppModule的子类,该方法看起来与此完全相同,并且不将其标记为类定义上方的模块:

    public class TestAppModule extends AppModule{
    
        public TestAppModule(Application application) {
            super(application);
        }
    
        @Override
        public ApplicationMode provideApplicationMode(){
            return ApplicationMode.TESTING; //notice we are testing here
        }
    }
    

    现在,在自定义测试运行器中声明的MyTestApplication类中声明了以下内容:

    public class PomeloTestApplication extends PomeloApplication {
    
        @Singleton
        @Component(modules = {AppModule.class})
        public interface TestAppComponent extends AppComponent {
            }
    
        @Override
        protected AppComponent initDagger(Application application) {
            return DaggerPomeloTestApplication_TestAppComponent.builder()
                    .appModule(new TestAppModule(application)) //notice we pass in our Test appModule here that we subclassed which has a ApplicationMode set to testing
                    .build();
        }
    }
    

    现在使用它只需将其注入 生产环境 代码中,无论如何:

    @Inject
        ApplicationMode appMode;
    

    因此,当您运行espresso测试时,它将测试枚举,但在 生产环境 代码中,它将是正常的枚举 .

    ps不是必需的,但是如果你需要看看我的 生产环境 匕首如何构建图形,就像这样并在应用程序子类中声明:

    protected AppComponent initDagger(Application application) {
            return DaggerAppComponent.builder()
                    .appModule(new AppModule(application))
                    .build();
        }
    

相关问题