How to determine if Android Application is started with JUnit testing instrumentation?
Asked Answered
W

3

24

I need to determine in runtime from code if the application is run under TestInstrumentation.

I could initialize the test environment with some env/system variable, but Eclipse ADK launch configuration would not allow me to do that.

Default Android system properties and environment do not to have any data about it. Moreover, they are identically same, whether the application is started regularly or under test.

This one could be a solution: Is it possible to find out if an Android application runs as part of an instrumentation test but since I do not test activities, all proposed methods there won't work. The ActivityManager.isRunningInTestHarness() method uses this under the hood:

SystemProperties.getBoolean("ro.test_harness") 

which always returns false in my case. (To work with the hidden android.os.SystemProperties class I use reflection).

What else can I do to try to determine from inside the application if it's under test?

Wong answered 26/1, 2014 at 18:46 Comment(0)
W
33

I have found one hacky solution: out of the application one can try to load a class from the testing package. The appication classloader surprisingly can load classes by name from the testing project if it was run under test. In other case the class is not found.

private static boolean isTestMode() {
  boolean result;
  try {
    application.getClassLoader().loadClass("foo.bar.test.SomeTest");
    // alternatively (see the comment below):
    // Class.forName("foo.bar.test.SomeTest");
    result = true;
  } catch (final Exception e) {
result = false;
  }
  return result;
}

I admit this is not elegant but it works. Will be grateful for the proper solution.

Wong answered 26/1, 2014 at 21:41 Comment(1)
I have an idea that I thought I'd share: In order to not make isTestMode() depend on one of my actual test classes (which are not unlikely to get renamed or deleted) I added an empty class called InstrumentationTestIndicator in my 'androidTest' directory which isTestMode() then tries to load. Thank you so much for this! I just adopted this hack into my project!Azov
M
16

The isTestMode() solution did not work for me on Android Studio 1.2.1.1. Almighty Krzysztof from our company tweaked your method by using:

Class.forName("foo.bar.test.SomeTest");

instead of getClassLoader(). Thanks for Krzysztof!

Mcallister answered 18/5, 2015 at 9:45 Comment(1)
yeah, Krzysztofs tend to be like thatRuminate
C
3

We created a solution to pass parameters to the MainActivity and use it inside the onCreate method, enabling you to define how the Activity will be created.

In MainActivity class, we created some constants, which could also be an enum. We created a static attribute too.

public class MainActivity {
    public static final int APPLICATION_MODE = 5;
    public static final int UNIT_TEST_MODE = 10;
    public static final int OTHER_MODE = 15;

    public static int activityMode = APPLICATION_MODE;
    (...)

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        switch (activityMode) {
            case OTHER_MODE:
                (...)
                break;

            case UNIT_TEST_MODE:
                Log.d(TAG, "Is in Test Mode!");
                break;

            case APPLICATION_MODE:
                (...)
                break;
        }
        (...)
    }
    (...)
}

We made MainActivityTest class abstract, created a setApplicationMode and called this method inside the setUp() method, before calling the super.setUp() method.

public abstract class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {

    protected void setUp() throws Exception {
        setApplicationMode();  // <=====
        super.setUp();
        getActivity();
        (...)
    }

    (...)
    public void setApplicationMode() {
        MainActivity.activityMode = MainActivity.UNIT_TEST_MODE;
    }
}

All other test classes inherit from MainActivityTest, if we want it to have another behaviour, we can simply override the setApplicationMode method.

public class OtherMainActivityTest extends MainActivityTest {
    (...)
    @Override
    public void setApplicationMode() {
        MainActivity.activityMode = MainActivity.OTHER_MODE;
    }
}

The user nathan-almeida is the friend that is co-author of this solution.

Choosey answered 26/2, 2015 at 13:32 Comment(2)
Great you found a solution but OH MY GOD - this is a nightmare to handle for every activity in a complex App. Further, you are going to ship into production with all this code..Dumuzi
This will become a nightmare for maintenance and readability as the activities of the application increases. The production application should have no knowledge of unit tests or automation tests. However, TDD (test driven development) can be practiced when designing/implementing production code to make unit and automation tests easier to implement.Chert

© 2022 - 2024 — McMap. All rights reserved.