I have the following Activity:
package codeguru.startactivityforresult;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class ChildActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.child);
this.resultButton = (Button) this.findViewById(R.id.result_button);
this.resultButton.setOnClickListener(onResult);
}
private View.OnClickListener onResult = new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent result = new Intent();
result.putExtra(ChildActivity.this.getString(R.string.result), ChildActivity.this.getResources().getInteger(R.integer.result));
ChildActivity.this.setResult(RESULT_OK, result);
ChildActivity.this.finish();
}
};
private Button resultButton = null;
}
And the following JUnit test:
package codeguru.startactivityforresult;
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.Button;
import junit.framework.Assert;
public class ChildActivityTest extends ActivityInstrumentationTestCase2<ChildActivity> {
public ChildActivityTest() {
super(ChildActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
this.setActivityInitialTouchMode(false);
this.activity = this.getActivity();
this.resultButton = (Button) this.activity.findViewById(R.id.result_button);
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
@UiThreadTest
public void testResultButtonOnClick() {
Assert.assertTrue(this.resultButton.performClick());
Assert.fail("How do I check the returned result?");
}
private Activity activity;
private Button resultButton;
}
How do I make sure that clicking the button sets the correct result (with the call to setResult()
) that will be returned to any activity which starts this acitivity with startActivityForResult()
?
With current Activity implementation in the question, i.e. by clicking button in ChildActivity set the result then destroy the activity immediately, there are not much we can do in the ChildActivityTest for testing result related stuff.
The answer in related question Testing onActivityResult() shows how to unit-test startActivityForResult() and/or onActivityResult() standalone in MainActivityTest. By standalone means MainActivityTest does not depend on ChildActivity's interaction, instrumentation will capture ChildActivity creation and kill it immediately then return a ready baked mock ActivityResult, hence unit test MainActivity.
If you don't want instrumentation interrupt and return the mock ActivityResult, you can let ChildActivity keep going then simulating the interaction in ChildActivity consequently and return the real ActivityResult back to MainActivity. Says if you MainActivity start ChildActivity for result then update a TextView, to test the the whole end-to-end interaction/cooperation, see sample code below:
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
... ...
public void testStartActivityForResult() {
MainActivity mainActivity = getActivity();
assertNotNull(activity);
// Check initial value in TextView:
TextView text = (TextView) mainActivity.findViewById(com.example.R.id.textview1);
assertEquals(text.getText(), "default vaule");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Create an ActivityMonitor that monitor ChildActivity, do not interrupt, do not return mock result:
Instrumentation.ActivityMonitor activityMonitor = getInstrumentation().addMonitor(ChildActivity.class.getName(), null , false);
// Simulate a button click in MainActivity that start ChildActivity for result:
final Button button = (Button) mainActivity.findViewById(com.example.R.id.button1);
mainActivity.runOnUiThread(new Runnable() {
public void run() {
button.performClick();
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
getInstrumentation().waitForIdleSync();
ChildActivity childActivity = (ChildActivity) getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 5);
// ChildActivity is created and gain focus on screen:
assertNotNull(childActivity);
// Simulate a button click in ChildActivity that set result and finish ChildActivity:
final Button button2 = (Button) childActivity.findViewById(com.example.R.id.button1);
childActivity.runOnUiThread(new Runnable() {
public void run() {
button2.performClick();
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
getInstrumentation().waitForIdleSync();
// TextView in MainActivity should be changed:
assertEquals(text.getText(), "default value changed");
}
... ...
}
I add three Thread.sleep() calls here so that you can get a chance see the button clicking simulation when running JUnit Test. As you can see here, a standalone ChildActivityTest is not sufficient to test the whole cooperation, we are actually testing ChildActivity.setResult() indirectly via MainActivityTest, as we need simulate the whole interaction from the very beginning.
May I recommend using Robotium framework. Robotium uses a class Solo, which has a very helpful API .
It allows you to see what the current activity is. Allows you to assert that an activity has started etc.
http://code.google.com/p/robotium/
After performing click you can do something like
void assertCurrentActivity(java.lang.String message, java.lang.Class expectedClass, boolean isNewInstance) So heres what I would do. After the code to click the button
Activity callingActvity = solo.getCurrentActivity();
solo.assertCurrentActivity("ShouldbeCallingActivity","NameOfCallingActivity");
I cannot give a full solution without knowing how the callback works. But assuming that some text shows up for RESULT_OK as opposed to some other text ,
you can do something like
assertTrue(solo.waitForText("Text that is supposed to show for Result OK");
PS: robotium will only work for activities in same application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With