Question

Need a workaround to stop long unit tests running on AVD from ADT . Stop button in JUnit view doesn't work, neither Stop button in debug view. Even though it prints that VM was terminated. Example:

public class StopTest extends AndroidTestCase {

    public void testSleep() throws Exception {
        Thread.sleep(20000);
    }
}

Possible solution:

Show the cancel button on device screen.

I managed to create a new Activity with a button in my test project. Unfortunately, the tests suite was executed in the context of the application I test. So, to start this activity I would need to edit the app manifest, which I didn't want to. So I added this activity to the test manifest and start it from InstrumentationTestCase.getInstrumentation().getContext().

With this my activity with a button appears on screen, but it's started in another process. Now I need something to send a message from the activity to the application I test.

Don't want to add a service to my app, because, as I told, I don't want to edit the app manifest.

Is it possible to send a Binder to the activity and use it to send messages back?

Was it helpful?

Solution

In setUp() I start activity with a button. When pressed, I broadcast action back, and call System.exit() in receiver.

==> ./src/org/foo/StopButtonInstrumentationTestCase.java <==
...
public class StopButtonInstrumentationTestCase extends InstrumentationTestCase {

        public void testSleep() throws Exception {
                Thread.sleep(10000);
        }

        public void testSleep2() throws Exception {
                Thread.sleep(10000);
        }

        @Override
        protected void setUp() throws Exception {
                super.setUp();
                showStopButton(getInstrumentation(), getName());
        }

        @Override
        protected void tearDown() throws Exception {
                hideStopButton(getInstrumentation());
                super.tearDown();
        }

        private static final BroadcastReceiver receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                        System.exit(1);
                }
        };

        public static void showStopButton(Instrumentation instrumentation, String testName) {
                // register stop tests receiver
                Context targetCtx = instrumentation.getTargetContext();
                targetCtx.registerReceiver(receiver, new IntentFilter(StopperActivity.ACTION));

                // show stop tests button
                Context ctx = instrumentation.getContext();
                Intent intent = new Intent(ctx, StopperActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                intent.putExtra(StopperActivity.PARAM_TEST_NAME, testName);
                ctx.startActivity(intent);
        }

        public static void hideStopButton(Instrumentation instrumentation) {
                Context targetCtx = instrumentation.getTargetContext();
                targetCtx.unregisterReceiver(receiver);
                // hide stop tests button
                Context ctx = instrumentation.getContext();
                Intent intent = new Intent(ctx, StopperActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); // android:launchMode="singleTop" doesn't work in old versions
                intent.putExtra(StopperActivity.PARAM_KILL, true);
                ctx.startActivity(intent);
        }
}

==> ./src/org/foo/StopperActivity.java <==
...
public class StopperActivity extends Activity {

        public static final String ACTION = StopperActivity.class.getName() + ".ACTION";
        public static final String PARAM_TEST_NAME = "testName";
        public static final String PARAM_KILL = "kill";

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

                setContentView(R.layout.activity_stopper);

                findViewById(R.id.stop_button).setOnClickListener(
                                new View.OnClickListener() {
                                        @Override
                                        public void onClick(View view) {
                                                stopTest();
                                        }
                                });
                Intent intent = getIntent();
                Bundle extras = intent.getExtras();
                if (extras != null) {
                        displayTestName(extras);
                }
        }

        @Override
        protected void onNewIntent(Intent intent) {
                super.onNewIntent(intent);
                Bundle extras = intent.getExtras();
                if (extras != null) {
                        if (extras.containsKey(PARAM_KILL)) {
                                finish();
                        } else {
                                displayTestName(extras);
                        }
                }
        }

        private void stopTest() {
                sendBroadcast(new Intent(ACTION));
                finish();
        }

        private void displayTestName(Bundle extras) {
                String testName = extras.getString(PARAM_TEST_NAME);
                if (testName == null)
                        testName = "";
                setTitle(testName);
        }
}

==> ./res/layout/activity_stopper.xml <==
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="org.foo.StopperActivity" >

    <Button
        android:id="@+id/stop_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"

        android:layout_marginTop="16dp"
        android:paddingLeft="32dp"
        android:paddingRight="32dp"

        tools:ignore="HardcodedText"
        android:text="Stop test" />

</merge>

==> AndroidManifest.xml <==
...
<!-- android:exported="true" - allow launch test activity in context of testee -->
<activity
    android:name="org.foo.StopperActivity"
    android:exported="true"
    android:windowSoftInputMode="adjustResize|stateVisible">
</activity>
...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top