47

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?

Vladimir Ivanov
  • 42,730
  • 18
  • 77
  • 103
user739684
  • 473
  • 1
  • 4
  • 5

7 Answers7

30

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...

MichK
  • 3,202
  • 3
  • 29
  • 33
  • assertThat(intent.getComponent()).isEqualTo(new ComponentName(activity, MySecondActivity.class)); Not working for me Its saying cant pass Component Type in assertThat() method – Abhijit Chakra Oct 09 '14 at 06:26
  • @AbhijitChakra review your Assertions imports. This examples are using Fest, try to use: org.fest.assertions.api.Assertions.assertThat(intent...) – Patrick Feb 02 '15 at 13:21
  • Intent intent = shadowActivity.peekNextStartedActivityForResult().intent; gives back NULL – narancs Sep 01 '15 at 14:54
  • 2
    for shadowing: use Shadows.shadowOf(), it changed in Robolectric 3.0. For further reference about other changes, see this guide – narancs Sep 01 '15 at 15:16
  • The upgrade guide is https://github.com/robolectric/robolectric/wiki/2.4-to-3.0-Upgrade-Guide – karl Feb 23 '16 at 19:15
  • As of Robolectric 3.0 you need to use an extractor as in: ShadowActivity sa = (ShadowActivity) ShadowExtractor.extract(activity); – Maks Jul 21 '16 at 02:04
  • CAREFUL!!!, `.nextStartedService` returns the item at `index[0]` and removes it from the List. Therefore, if you call `.nextStartedService` a second time, it will return null in the case you only started one Service. The same happens with `.nextStartedActivity`. Written in Kotlin – ArtiomLK Feb 13 '18 at 18:27
  • In androidx, creating an activity should be easily done by using `val mainActivity = ActivityScenario.launch(MainActivity::class.java)` and then calling `mainActivity.onActivity{ activity: MainActivity -> //code }` – laim2003 Jun 01 '20 at 18:52
20

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()); 
Ole
  • 480
  • 4
  • 11
James Neville
  • 201
  • 2
  • 2
  • Wow, that's a lot of changes over time. This one worked tho, so kudos. – CorayThan Jan 25 '17 at 23:39
  • Any idea of how to do this from a fragment? In particular when you're testing a fragment via `startFragment` - https://stackoverflow.com/a/21294337/5111113 – Huw Davies Jul 17 '18 at 07:59
18

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));
    }  
}
Scott Bale
  • 10,649
  • 5
  • 33
  • 36
  • assertThat causes error: The method assertThat(T, Matcher) in the type Assert is not applicable for the arguments (MainActivity, Intent) – user739684 May 28 '11 at 11:41
  • Sorry, you're right. I corrected the answer. Needs to take an Intent, not an activity. We internally use a helper method that reads "assertThat(activity, started(NextActivity.class));" - much more readable. – Scott Bale May 30 '11 at 04:27
  • Thought this worked initially and upvoted but it doesn't. Where does this test intercept the Intent raised in performClick? All this test does is construct two Intents and checks if they are equal - which they will never be. Could you clarify this code? – JDT Jun 13 '11 at 21:57
  • @JDT you are right, I corrected the last line of my answer. Thanks. – Scott Bale Jul 20 '11 at 20:00
  • @Dongshengcn, Test9Runner is a custom JUnit test runner from the original question, presumably one that extends Robolectric's RobolectricTestRunner. – Scott Bale Jul 20 '11 at 20:00
  • 40
    StartedMatcher was removed when robolectric moved to 2.0. Not sure what, if anything, replaced it. – gdw2 Oct 07 '13 at 19:49
7

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)));
}
Ari Lacenski
  • 631
  • 12
  • 18
  • 1
    equalTo() not working what type of method can you please confirm me because its not working for me..May be i am doing some wrong approach is it a robolectric method – Abhijit Chakra Oct 09 '14 at 06:38
2
@Before
public void setUp() throws Exception {
    mMainActivity = Robolectric.buildActivity(MainActivity.class)
            .create().start().visible().get();

    shadowActivity =Shadows.shadowOf(mMainActivity);
    hourlyButton = (Button) mMainActivity.findViewById(R.id.hourlyButton);
}
@Test
public void hourlyActivityButtonTest() throws Exception {

   Thread.sleep(5000);
    hourlyButton.performClick();
    Intent intent = shadowActivity.peekNextStartedActivityForResult().intent;
    assertThat(intent.getComponent()).isEqualTo(new ComponentName(mMainActivity, HourlyForecastActivity.class));

}
Gueorgui Obregon
  • 5,077
  • 3
  • 33
  • 57
2

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)
    }
}
OzzyTheGiant
  • 711
  • 8
  • 21
1

This is how does it looks like for the Robolectric 3

        // Click on the image view
    mShareLocationImageView.performClick();

    // Check the startActivityForResult for ShareUserLocationActivity has been triggered
    ShadowActivity shadowActivity = Shadows.shadowOf(mChatWindowsActivity);
    Intent intent = shadowActivity.peekNextStartedActivityForResult().intent;
    assertThat(intent).hasComponent(new ComponentName(mChatWindowsActivity, ShareUserLocationActivity.class));
jiahao
  • 3,373
  • 2
  • 35
  • 36