5

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()?

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • possible duplicate of [Testing onActivityResult()](http://stackoverflow.com/questions/13042015/testing-onactivityresult) – John B Oct 24 '12 at 10:49
  • @JohnB This is a related but totally different question. Here I am asking how to test the "child" activity. The question that you give as a possible duplicate asks about testing the "parent" activity. I decided to post them as two separate questions so that I could ask two focused questions rather than hiding the two questions in between a lot of code. – Code-Apprentice Oct 24 '12 at 18:46

2 Answers2

6

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.

Community
  • 1
  • 1
yorkw
  • 40,926
  • 10
  • 117
  • 130
  • Thank you for your patience. I think you repeated much of what you stated in my other question, but it's starting to click a little bit more now. One possible mistake I see that I made is that I call `waitForMontiorWithTimeOut()` on the UI thread. [Would this result in a `null` (because the time out is reached)](http://stackoverflow.com/questions/13105202/starting-another-activity-in-a-junit-test-by-simulating-a-button-press)? – Code-Apprentice Oct 28 '12 at 23:26
1

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.

smk
  • 5,340
  • 5
  • 27
  • 41
  • This still doesn't answer my question. As you can see in my code, the OnClickListener calls `Activity.setResult()`. I want to add code (probably including assertions) to my JUnit test to check what the result was set to. Does Robotium do this? Better yet, how can I do it with the standard Android API? – Code-Apprentice Oct 24 '12 at 02:03
  • So can't you do something like assert that current activity is parent activity . And check the result? – smk Oct 24 '12 at 02:11
  • That's my question. How do I do that? (I'll certainly look into robotium in the near future. I'm just barely starting with Android testing -- as in about a week ago -- so I want to learn how to do this with it before checking out other APIs.) – Code-Apprentice Oct 24 '12 at 02:13
  • assertCurrentActivity(String message, Class parent activity.class) or waitForActivity(parentActivity,TIMEOUT) – smk Oct 24 '12 at 02:16
  • What classes contain those methods and how do I check the result? – Code-Apprentice Oct 24 '12 at 02:49
  • 1
    While I appreciate the suggestiong to check out Robotium, this does not answer my question. – Code-Apprentice Oct 24 '12 at 20:56
  • Well, there are more than 1 means to an end. This is one way (and probably the easiest) way to solve a problem. Thanks. – smk Oct 24 '12 at 21:02
  • 1
    That's my point. Your suggestions don't lead me to the end that I'm heading towards. Your answer does not address the main question about how to check the result stored by the call to `setResult()`. – Code-Apprentice Oct 24 '12 at 21:11