Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

testing Intent in android

I have an android app. When the user clicks button A and intent is fired like this android-presudocode :)

//inside FirstActivity
@Override
public void onClick(View view) {
    startActivity(new Intent(this, AnotherActivity.class));
}

So if I'm not mistaken, the onResume method in AnotherActivity should be called, right?

I use ActivityInstrumentationTestCase2<FirstActivity> to test my activity but I'm unable to instantiate AnotherActivity.

So the question is, how can I test this: 'When a button is pressed, the correct activity is resumed and the correct extras are passed to the intent'.

like image 727
fernandohur Avatar asked Oct 19 '25 01:10

fernandohur


2 Answers

You can use the instrumentation to make an ActivityMonitor. This will monitor if a new activity has been started.

ActivityMonitor am = getInstrumentation().addMonitor(Activity3.class.getName(), null, true;

Then you want to use button.performClick() to "press the button". Finally, you check if the activity monitor has been hit.

am.waitForActivitywithTimeout(timeout);
assertEquals(1, am.getHits());

I haven't used ActivityInstrumentationTestCase2 in quite a while so I don't guarantee these steps are exactly right. In any case, I recommend that you take a look at Robolectric: a wonderful unit testing framework for Android that will change your life. It will help you overcome many situations that are difficult or impossible to test with any of the default instrumentation tests.

like image 151
aleph_null Avatar answered Oct 22 '25 04:10

aleph_null


So after some time I want to post the solution that I use almost always. Initially I liked @aleph_null's solution but it turns out that it makes tests unbearably slow so this is what I use now:

First, I have this interface

/**
 * Simple interface to launch other activities.
 */
public interface ActivityLauncher {

    /**
     * Starts an activity with the Intent provided.
     * @param intent an intent
     */
    public void start(Context context, Intent intent);

    /**
     *
     * Returns the intent as set by {@link #start(android.content.Context,     android.content.Intent) start} or null if not yet
     * called.
     *
     * @return an intent or null
     */
    public Intent getIntent();
}

And I have two implementations for it:

/**
 * Default implementation of ActivityLauncher
 */
public class DefaultActivityLauncher implements ActivityLauncher{

    private Intent intent;

    public DefaultActivityLauncher(){}

    @Override
    public void start(Context context, Intent intent) {
        this.intent = intent;
        context.startActivity(intent);
    }

    @Override
    public Intent getIntent() {
        return intent;
    }
}

and

/**
 * Mock implementation of ActivityLauncher that simply sets the intent but does not actually starts
 * an activity.
 */
public class MockActivityLauncher implements ActivityLauncher {

    private Intent intent;

    @Override
    public void start(Context context, Intent intent) {
        this.intent = intent;
    }

    @Override
    public Intent getIntent() {
        return intent;
    }
}

Then I use a dependency injection framework like Dagger or similar like this:

 public class MyActivity {

    @Inject ActivityLauncher launcher;

    public void onCreate(Bundle bundle){

        // some code omitted for brevity
        findViewById(R.id.goToOtherActivityButton).setOnClick(new OnClickListener(){
           Intent intent = new Intent(getContext(), MyOtherActivity.class);
           launcher.start(getContext(), intent);
        });
    }

    public ActivityLauncher getLauncher(){
        return launcher;
    }
}

Testing is then as simple as checkIntentIsValid(activity.geLauncher().getIntent())

like image 25
fernandohur Avatar answered Oct 22 '25 03:10

fernandohur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!