Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Robolectric to test code that starts an activity

I have some code I want to test with Robolectric. Basically I want to test that a button click launches an activity.

HomeScreenFragment.java:

public class HomeScreenFragment extends Fragment {

    private Button mSignInButton;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState); // call to super class
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup parent,
                             Bundle savedInstanceState){

        // inflate view
        View view = inflater.inflate(R.layout.fragment_home_screen, parent, false);

        // handle sign in button
        mSignInButton = (Button)view.findViewById(R.id.sign_in_button);
        mSignInButton.setOnClickListener(new View.OnClickListener() {
            // anonymous inner class
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getActivity(), SignInActivity.class);// start sign in activity with intent
                startActivity(intent); // <<== ERROR HERE WHEN RUNNING TEST

            }
        }
    }
}

My test looks like this: HomeSreenFragmentTest.java:

@RunWith(RobolectricTestRunner.class)
public class HomeScreenFragmentTest {

    private Activity mHomeScreenActivity;
    private Fragment mTestFragment;
    private Button mSignInButton;

    @Before
    public void setup() throws Exception{

        mHomeScreenActivity = Robolectric.buildActivity(HomeScreenActivity.class).create().get(); // start HomeScreenActivity, call through to onCreate()
        mTestFragment = mHomeScreenActivity.getFragmentManager().findFragmentById(R.id.home_screen_fragment_container);// get HomeScreenFragment

        // run onCreateView
        View testView = mTestFragment.onCreateView(LayoutInflater.from(mHomeScreenActivity),
                (ViewGroup) mHomeScreenActivity.findViewById(R.id.home_screen_fragment_container),
                null);

        // get button view
        mSignInButton = (Button)testView.findViewById(R.id.sign_in_button);

    }

    // clicking sign in button should launch SignInActivity
    @Test
    public void testSignInButton2() throws Exception{
        mSignInButton.performClick(); <<=== ERROR STARTS HERE
        ShadowActivity shadowActivity = Robolectric.shadowOf(mHomeScreenActivity); // create shadow activity
        Intent startedIntent = shadowActivity.getNextStartedActivity();            // get intent of next activity on stack
        ShadowIntent shadowIntent = Robolectric.shadowOf(startedIntent);            // create shadow intent which starts next activity
        assertEquals(SignInActivity.class.getName(), shadowIntent.getComponent().getClassName()); // compare shadow intent w/ desired next activity
    }

The problem I am having is with the test. The code itself works fine in emulator/on device. The problem is that when Robolectric runs the performClick() method, and then gets to onClick() then goes to startActivity(intent) it fails.

Stacktrace:

java.lang.NullPointerException: null
    at android.app.Activity.startActivityFromFragment(Activity.java:3850)
    at android.app.Activity.startActivityFromFragment(Activity.java:3825)
    at android.app.Fragment.startActivity(Fragment.java:996)
    at android.app.Fragment.startActivity(Fragment.java:975)
    at com.********.android.***project*****.controller.HomeScreenFragment$1.onClick(HomeScreenFragment.java:42)
    at android.view.View.performClick(View.java:4084)
    at com.*********.android.***project***.HomeScreenFragmentTest.testSignInButton2(HomeScreenFragmentTest.java:83)

I know how to start an activity with Robolectric using the Robolectric.buildActivity() method. But this is for when I need an activity in testing. Why is Robolectric failing to run the startActivity() method in code? Is there a better way to test this?

like image 766
tir38 Avatar asked Oct 18 '13 16:10

tir38


1 Answers

You should also call .start().resume() on your ActivityController, not only .create() This causes the fragment to be created as well.

If you do the above, you won't need to call onCreateView yourself. You can just get the button from the activity using mHomeScreenActivity.findViewById(R.id.sign_in_button);

In general I suspect your code fails because the fragment hasn't fully started yet, because you didn't call start() and resume()

like image 73
Jeroen Avatar answered Oct 04 '22 01:10

Jeroen