'How to convert Android SingleLaunchActivityTestCase to ActivityTestRule? (Instrumentation unit test)

The documentation for SingleLaunchActivityTestCase says that this class is now deprecated, and it should be replaced with ActivityScenarioRule or ActivityTestRule. But how is this done?

SingleLaunchActivityTestCase allowed an Activity to launch once and keep it open; then multiple tests can run during this time, then the Activity is closed. ActivityTestRule does not seem to have this functionality - it always relaunches the Activity for each @Test method.

So is it possible to make ActivityTestRule launch an Activity once and keep it open, and how do I ensure the context (from activityTestRule.getActivity()) is not null for each @Test function?

Example code here.



Solution 1:[1]

Use the constructor that does not start the activity by default (setting the launchActivity argument to false). Then use launchActivity() in your setup, but not in each test method. This way you will start it up once yourself, but each test will operate on the same instance.

You'll probably want to also explicitly finish the activity at the end of the test class, for cleanup.

Note: This isn't generally a best practice for testing though, since tests could depend on each other (which isn't a good idea), or provide incorrect results depending on the order they run, etc. since the activity state is persisted from one test to the next in this case.

Solution 2:[2]

I used Jon Adams answer to elaborate with an example:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class KeepActivityOpenDuringTests {

    @Rule
    public ActivityTestRule<MyActivity> activityTestRule =
            new ActivityTestRule<>(MyActivity.class, true, false);

    /**
     * When running the class as a test suite, setUp() is called repeatedly
     * for each test method. Use setupDone to prevent multiple setups.
     */
    private static boolean setupDone;
    // Static to persist across multiple tests
    private static Context context;
    private static MyActivity activityUnderTest;

    @Before
    public void setUp() throws Exception {
        // Launch the Activity manually, once, to get a real Context object.
        if (!setupDone) {
            activityUnderTest = activityTestRule.launchActivity(null);
            context = (Context) activityUnderTest;
            // continue setup of singletons...
            setupDone = true;
        }
    }

    @Test
    public void test1() {
        // Use context ...
    }

    @Test
    public void test2() {
       // Use activityUnderTest ...
    }

    @AfterClass
    public static void cleanUp() throws Exception {
        if (activityUnderTest != null) {
            activityUnderTest.finish();
            // Prevent any potential memory leaks
            activityUnderTest = null;
            context = null;
            setupDone = false;
        }
    }
}

It works like SingleLaunchActivityTestCase, when the tests are run as a class or individually.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jon Adams
Solution 2 Mr-IDE