user1730789 user1730789 - 28 days ago 14
Android Question

Android Instrumentation Launch Activity

I have a simple activity that contains a button. When i press the button a second activity runs. Now I am new to Android Instrumentation Testing. So far this is what I have written

public class TestSplashActivity extends
ActivityInstrumentationTestCase2<ActivitySplashScreen> {

private Button mLeftButton;
private ActivitySplashScreen activitySplashScreen;
private ActivityMonitor childMonitor = null;
public TestSplashActivity() {
super(ActivitySplashScreen.class);
}

@Override
protected void setUp() throws Exception {
super.setUp();
final ActivitySplashScreen a = getActivity();
assertNotNull(a);
activitySplashScreen=a;
mLeftButton=(Button) a.findViewById(R.id.btn1);

}

@SmallTest
public void testNameOfButton(){
assertEquals("Press Me", mLeftButton.getText().toString());
this.childMonitor = new ActivityMonitor(SecondActivity.class.getName(), null, true);
this.getInstrumentation().addMonitor(childMonitor);
activitySplashScreen.runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
mLeftButton.performClick();
}});

Activity childActivity=this.getInstrumentation().waitForMonitorWithTimeout(childMonitor, 5000);
assertEquals(childActivity, SecondActivity.class);

}


}

Now the first assert where I get the text of the button works. But when I call the perform click, I get an exception

Only the original thread that created a view hierarchy can touch its views.


Now I understand this exception in the context of Android applications, but now in the terms of instrumentation testing. How can I perform the click event on the button, and how can I check whether my second activity has been loaded.

Answer

Assuming you have a test class which extends InstrumentationTestCase, and that you are in a test method, it should follow this logic:

  1. Register your interest in the activity you want to check.
  2. Launch it
  3. Do what you want with it. Check if components are right, perform user actions, and that kind of thing.
  4. Register your interest for the next activity in the "sequence"
  5. Perform the action of that activity which makes the next activity of the sequence pop up.
  6. Repeat, following this logic...

In terms of code, this would result in something like the following:

Instrumentation mInstrumentation = getInstrumentation();
// We register our interest in the activity
Instrumentation.ActivityMonitor monitor = mInstrumentation.addMonitor(YourClass.class.getName(), null, false);
// We launch it
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(mInstrumentation.getTargetContext(), YourClass.class.getName());
mInstrumentation.startActivitySync(intent);

Activity currentActivity = getInstrumentation().waitForMonitor(monitor);
assertNotNull(currentActivity);
// We register our interest in the next activity from the sequence in this use case
mInstrumentation.removeMonitor(monitor);
monitor = mInstrumentation.addMonitor(YourNextClass.class.getName(), null, false);

To send clicks, do something like the following:

View v = currentActivity.findViewById(....R.id...);
assertNotNull(v);
TouchUtils.clickView(this, v);
mInstrumentation.sendStringSync("Some text to send into that view, if it would be a text view for example. If it would be a button it would already have been clicked by now.");