Testing that button starts an Activity with Robolectric

Hi I have the following code:

@RunWith(Test9Runner.class)
public class MainActivityTest 
{
    private MainActivity activity;
    private Button pressMeButton;

    @Before
    public void setUp() throws Exception 
    {
        activity = new MainActivity();
        activity.onCreate(null);
        pressMeButton = (Button) activity.findViewById(R.id.button1);
    }

    @Test
    public void shouldUpdateResultsWhenButtonIsClicked() throws Exception 
    {
        pressMeButton.performClick();
        ShadowActivity shadowActivity = shadowOf(activity);
        Intent intent = shadowActivity.getResultIntent();
        System.out.print(intent.toString());
    }
}

But I have no idea how to test that pressing pressMeButton started a new Activity. Actually it does, but how to write the correct Robolectric unit test for this fact?


Solution 1:

In Robolectric 2.1.1 you can verify if Intent starting new Activity was emitted in following way.

@RunWith(RobolectricTestRunner.class)
public class MyTest {
  private ShadowActivity shadowActivity;
  private MyActivity activity;

  @Before
  public void setup() {
    activity = new MyActivity();
    shadowActivity = Robolectric.shadowOf(activity);        
  }

  @Test
  public shouldStartNewActivityWhenSomething() {
    //Perform activity startup
    //Do some action which starts second activity, for example View::performClick()
    //...
    //Check Intent
    Intent intent = shadowActivity.peekNextStartedActivityForResult().intent;
    assertThat(intent.getStringExtra(MySecondActivity.EXTRA_MESSAGE)).isEqualTo("blebleble");
    assertThat(intent.getComponent()).isEqualTo(new ComponentName(activity, MySecondActivity.class));
  }
}

This is similar to what I am doing. Please note that creating Activity by calling new Activity() will make Robolectric print warnings about creating activity improperly, this probably can be done better...

Solution 2:

Updating this for 3.1.2 as the answers above did not work for me:-

    loginButton.callOnClick();

    Intent startedIntent = shadowOf(activity).getNextStartedActivity();
    ShadowIntent shadowIntent = shadowOf(startedIntent);
    assertEquals(NextActivity.class, shadowIntent.getIntentClass()); 

Solution 3:

Use Robolectric's StartedMatcher

@RunWith(Test9Runner.class) 
public class MainActivityTest  {
    private MainActivity activity;
    private Button pressMeButton;

    @Before
    public void setUp() throws Exception 
    {
        activity = new MainActivity();
        activity.onCreate(null);
        pressMeButton = (Button) activity.findViewById(R.id.button1);
    }

    @Test
    public void shouldStartNextActivityWhenButtonIsClicked() 
    {
        pressMeButton.performClick();
        assertThat(activity, new StartedMatcher(NextActivity.class));
    }  
}

Solution 4:

Inspired by @MichK's answer, here is a complete running test using the buildActivity method chain from Robolectric 2.2+:

@Test
public void testStartScheduleActivity() {
    HomeScreenActivity homeActivity = Robolectric.buildActivity(HomeScreenActivity.class).create().start().visible().get();
    ShadowActivity shadowHome = Robolectric.shadowOf(homeActivity);
    Button btnLaunchSchedule = (Button) homeActivity.findViewById(R.id.btnLaunchSchedule);
    Robolectric.clickOn(btnLaunchSchedule);

    assertThat(shadowHome.peekNextStartedActivityForResult().intent.getComponent(), equalTo(new ComponentName(homeActivity, ScheduleActivity.class)));
}

Solution 5:

James Neville's answer works on 4.3. However, I used the AndroidX API, Espresso and Kotlin:

// scenario initialization is done in @Before setUp method, I did it here for brevity
val scenario = ActivityScenario.launch(MainActivity::class.java)

@Test fun test() {
    onView(withId(R.id.button_id)).perform(click())

    scenario.onActivity { activity ->
        val intent = shadowOf(activity).nextStartedActivity
        val shadowIntent = shadowOf(intent)

        assertEquals(SearchResultsActivity::class.java, shadowIntent.intentClass)
    }
}