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

Com*_*ler 21 android ui-testing android-espresso

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

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

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

Com*_*ler 30

结合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 ();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 那么只使用布尔(非布尔)对象而不是AtomicBoolean类呢? (3认同)
  • 这种`AtomicBoolean`的使用不是线程保存.你需要使用一个最终的'AtomicBoolean`的setter而不是检查`null`并创建一个新的.目前,这与使用普通的`boolean`一样保存. (2认同)

Rya*_*yan 28

结合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();
    }
Run Code Online (Sandbox Code Playgroud)

  • 另一件事,迁移到 androidX 后应该是 -> `Class.forName("androidx.test.espresso.Espresso")` (7认同)

小智 13

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

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

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

if (isRunningTest) {
  // Espresso only code
}
Run Code Online (Sandbox Code Playgroud)

  • 喷射回来的androidx.test.espresso.Espresso (6认同)

Ken*_*chi 8

BuildConfig课堂上的旗帜怎么样?

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

将此添加到测试类中的某个位置。

static {
    BuildConfig.IS_TESTING.set(true);
}
Run Code Online (Sandbox Code Playgroud)

  • 这帮助我避免为测试时需要不同的一行编写大量代码 (3认同)

j2e*_*nue 5

我不想使用在 android 上运行缓慢的反射。我们大多数人都为依赖注入设置了 dagger2。我有一个用于测试的测试组件。以下是获取应用程序模式(测试或正常)的简要方法:

创建一个枚举:

public enum ApplicationMode {
    NORMAL,TESTING;
}
Run Code Online (Sandbox Code Playgroud)

和一个普通的 AppModule:

@Module
public class AppModule {

    @Provides
    public ApplicationMode provideApplicationMode(){
        return ApplicationMode.NORMAL;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记像这样在gradle中声明它:

defaultConfig {
testInstrumentationRunner "com.mobile.pomelo.base.PomeloTestRunner"
}
Run Code Online (Sandbox Code Playgroud)

现在使用 override 方法创建 AppModule 的子类,该方法看起来完全像这样,并且不要将其标记为类定义上方的模块:

public class TestAppModule extends AppModule{

    public TestAppModule(Application application) {
        super(application);
    }

    @Override
    public ApplicationMode provideApplicationMode(){
        return ApplicationMode.TESTING; //notice we are testing here
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在您在自定义测试运行程序中声明的 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在要使用它,只需将它注入到生产代码中,就像这样:

@Inject
    ApplicationMode appMode;
Run Code Online (Sandbox Code Playgroud)

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

ps 不是必需的,但如果您需要查看我的生产匕首如何构建图形并在应用程序子类中声明:

 protected AppComponent initDagger(Application application) {
        return DaggerAppComponent.builder()
                .appModule(new AppModule(application))
                .build();
    }
Run Code Online (Sandbox Code Playgroud)


hem*_*tsb 5

如果您将JitPack与 kotlin 一起使用。您需要更改Espresso 的包名称。

val isRunningTest : Boolean by lazy {
    try {
        Class.forName("androidx.test.espresso.Espresso")
        true
    } catch (e: ClassNotFoundException) {
        false
    }
}
Run Code Online (Sandbox Code Playgroud)

用于检查

if (isRunningTest) {
  // Espresso only code
}
Run Code Online (Sandbox Code Playgroud)