Get result from an activity after finish(); in an Android unit test

15,408

Solution 1

You can use reflection and grab the values directly from the Activity.

protected Intent assertFinishCalledWithResult(int resultCode) {
  assertThat(isFinishCalled(), is(true));
  try {
    Field f = Activity.class.getDeclaredField("mResultCode");
    f.setAccessible(true);
    int actualResultCode = (Integer)f.get(getActivity());
    assertThat(actualResultCode, is(resultCode));
    f = Activity.class.getDeclaredField("mResultData");
    f.setAccessible(true);
    return (Intent)f.get(getActivity());
  } catch (NoSuchFieldException e) {
    throw new RuntimeException("Looks like the Android Activity class has changed it's   private fields for mResultCode or mResultData.  Time to update the reflection code.", e);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

Solution 2

Or you could also use Robolectric and shadow the Activity under test. Then, ShadowActivity provides you with methods to easily know if an Activity is finishing and for retrieving its result code.

As an example, one of my tests looks like this:

@Test
public void testPressingFinishButtonFinishesActivity() {
    mActivity.onCreate(null);
    ShadowActivity shadowActivity = Robolectric.shadowOf(mActivity);

    Button finishButton = (Button) mActivity.findViewById(R.id.finish_button);
    finishButton.performClick();

    assertEquals(DummyActivity.RESULT_CUSTOM, shadowActivity.getResultCode());
    assertTrue(shadowActivity.isFinishing());
}

Solution 3

You can do this by writing a special activity whose only purpose is to start the activity you are testing for result and save the result for you to assert correctness on.

For example, you could create an activity named ResultReceiverActivity. Give it three methods: getResultCode, getResultData, and getReceivedRequestCode, which can be used to verify that the tested activity returned the right values. You would create a test case that extends ActivityInstrumentationTestCase2 and the generic parameter would be ResultReceiverActivity. Calling getActivity will get you the activity instance.

public class ReturnedResultTest 
    extends ActivityInstrumentationTestCase2<ResultReceiverActivity> {

    public void testReturnedResult() {
        ResultReceiverActivity a = getActivity();
        assertEquals(Activity.RESULT_OK, a.getResultCode());
        assertEquals("myResult", a.getResultData().getStringExtra("test"));
        assertEquals(0x9999, a.getReceivedRequestCode());
    }
}

ResultReceiverActivity needs to override onActivityResult, of course, and should just store the values of that methods parameter in its fields, like so:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    this.receivedRequestCode = requestCode;
    this.resultCode = resultCode;
    this.resultData = data;
}

Of course, you may want to customize the activity that ResultReceiverActivity starts, and you can easily do that by using getIntent in its onCreate method. In your test case, call setActivityIntent before calling getActivity to set which Intent is used to start the activity.

Share:
15,408
uvesten
Author by

uvesten

Updated on June 15, 2022

Comments

  • uvesten
    uvesten about 2 years

    I'm currently writing some Android unit tests, and while I've gotten most things to work the way I want, one thing has left me kind of stumped.

    I have the following code in my activity under test:

    Intent result = new Intent();
    result.putExtra("test", testinput.getText().toString());
    setResult(Activity.RESULT_OK, result);
    finish();
    

    I'm trying to figure out how to use Instrumentation (or whatever) to be able to read the result of the activity, or get at the intent after the activity is finished. Can anyone help?

  • uvesten
    uvesten about 13 years
    Yes, that's true, and thanks. However, I'm asking specifically about the unit testing case.
  • Marc Bernstein
    Marc Bernstein about 13 years
    Can you add a little bit more detail to the question about the specific issue you are seeing?
  • uvesten
    uvesten about 13 years
    Thanks, I'll test this! However, I've realized that my question should have been along the lines of: unit testing the result of an activity which takes user input. (I.e., the activity takes input from the screen.) Easy enough to test by itself, might be harder to unit test. Don't know if all of that could be called a "unit test", really...
  • coredump
    coredump almost 12 years
    Great! I am using this instead of getActivity.getResultCode() inside a unit test, and this works perfect
  • Guerneen4
    Guerneen4 over 5 years
    shadowActivity.isFinishing() is now deprecated, Activity provides directly that flag, simply use mActivity.isFinishing