Is it possible to find out if an Android application runs as part of an instrumentation test

Viewed 7456

Is there a runtime check for an application to find out if it runs as part of an instrumentation test?

Background: Our application performs a database sync when starting. But that should happen only when started regularly. It especially interferes with the instrumentation tests testing the db sync. Not surprisingly.

And with all the other tests it's just a waste of CPU cycles.

8 Answers

If you are using Robolectric, you can do something like this:

public boolean isUnitTest() {
        String device = Build.DEVICE;
        String product = Build.PRODUCT;
        if (device == null) {
            device = "";
        }

        if (product == null) {
            product = "";
        }
        return device.equals("robolectric") && product.equals("robolectric");
    }

d= (◕‿↼ ) Great answer, but if some library developer (like me) wants to know if the Host (or App using the library) is being tested, then try:

import android.content.pm.ApplicationInfo;

// ...

private static int wasTestRun = 0xDEAD;

/**
 * Should only be used to speed up testing (no behavior change).
 * @return true in tests, if Gradle has the right dependencies.
 */
public static boolean isTestRun(@NonNull Context context) {
    if (wasTestRun != 0xDEAD) {
        return wasTestRun != 0;
    }
    // Ignore release builds (as App may be using JUnit by mistake).
    if (isDebuggable(context)) {
        try {
            Class.forName("org.junit.runner.Runner");
            wasTestRun = 1;
            return true;
        } catch (ClassNotFoundException ignored) {
        }
    }
    wasTestRun = 0;
    return false;
}

public static boolean isDebuggable(@Nullable Context context) {
    return context != null && (context.getApplicationContext()
            .getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}

Note that I am not using any AtomicBoolean or other helpers, as it is already pretty fast (and locking may just bring the speed down).

You can try this

if (isRunningTest == null) {
        isRunningTest = false;
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        List<StackTraceElement> list = Arrays.asList(stackTrace);
        for (StackTraceElement element : list) {
            if (element.getClassName().startsWith("androidx.test.runner.MonitoringInstrumentation")) {
                isRunningTest = true;
                break;
            }
        }
    }
Related