How to run tests on an activities fragment

2019-01-26 10:16发布

I am just starting out wih junit and the first issue I'm running into is, how should I test fragments?

The activity being tested has 1 fragment which is the main layout.

@Override
protected void setUp() throws Exception {
    super.setUp();
    Intent intent = new Intent(getInstrumentation().getTargetContext(),
            ActivityWelcome.class);
    startActivity(intent, null, null);

    FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
    mFragmentWelcome = (FragmentWelcome) fragmentManager.findFragmentByTag(FragmentWelcome.TAG);
    if (mFragmentWelcome == null) {

        mFragmentWelcome= FragmentWelcome.newInstance();
        fragmentManager
                .beginTransaction()
                .replace(android.R.id.content, mFragmentWelcome, FragmentWelcome.TAG)
                .commit();
    }
}

I then go on to test the layout:

@SmallTest
public void testLayout() {

    ImageButton buttonImage = (ImageButton) getActivity().findViewById(my.package.R.id.button_invites);
    assertNotNull(buttonImage);
    assertEquals("ImageButton Invite has an invalid drawable"
            , getActivity().getResources().getDrawable(my.package.R.drawable.light_social_invite)
            , buttonImage);
}

Error:

java.lang.NullPointerException
    at my.package.test.ActivityWelcomeUnitTest.testLayout(ActivityWelcomeUnitTest.java:55)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
    at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
    at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
    at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
    at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:545)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1551)

it fails on:

ImageButton buttonImage = (ImageButton) mFragmentWelcome.getView().findViewById(my.package.R.id.button_invites);

I'm not sure why the fragment is null, I am obviously performing this operation incorrectly, could someone please enlighten me?

3条回答
老娘就宠你
2楼-- · 2019-01-26 10:47

Actually you have to wait for the UI thread composes the main view with the fragments.

I had the same errors and so I looked at the sources of Robotium to see how they handle that. The response is they use some methods that wait the required time.

For fragment you can use something like that before performing your assertions :

protected Fragment waitForFragment(String tag, int timeout) {
        long endTime = SystemClock.uptimeMillis() + timeout;
        while (SystemClock.uptimeMillis() <= endTime) {

            Fragment fragment = getActivity().getSupportFragmentManager().findFragmentByTag(tag);
            if (fragment != null) {
                return fragment;
            }
        }
        return null;
    }

I use a timeout of 5000ms, it seems to work well.

So in your code you should replace

mFragmentWelcome = (FragmentWelcome) fragmentManager.findFragmentByTag(FragmentWelcome.TAG);

by

mFragmentWelcome = (FragmentWelcome) waitForFragment(FragmentWelcome.TAG, 5000);

EDIT : This response assumes your junit extends ActivityInstrumentationTestCase2<T>

查看更多
家丑人穷心不美
3楼-- · 2019-01-26 10:52

For an ActivityUnitTestCase test, I had to add the following line(s) to the waitForFragment method:

// haven't really checked if this is necessary
getInstrumentation().waitForIdleSync();
// without this, waitForFragment() failed to find the fragment
getActivity().getFragmentManager().executePendingTransactions();
查看更多
时光不老,我们不散
4楼-- · 2019-01-26 11:06

U can use com.robotium.solo.Solo from 'com.jayway.android.robotium:robotium-solo:5.2.1'

    mInstrumentation = InstrumentationRegistry.getInstrumentation();
    mSolo = new Solo(mInstrumentation);
    mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    .....
    mSolo.waitForFragmentById();
查看更多
登录 后发表回答