如何在活动片段上运行测试

7

我刚开始使用 junit,遇到的第一个问题是如何测试片段?

被测试的活动有1个片段,它是主布局。

@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();
    }
}

我接着进行布局测试:
@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);
}

错误:

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)

它失败在:

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

我不确定为什么碎片(fragment)是 null,很明显我操作不正确,请问有谁可以帮我澄清一下吗?


你是如何运行单元测试的?在Android Studio中,我在这个Intent intent = new Intent(getInstrumentation().getTargetContext(), ActivityWelcome.class);处得到了空指针异常。我的测试类继承了ActivityUnitTestCase<TargetActivity> - Muhammad Babar
3个回答

9

实际上,您需要等待UI线程使用片段组合主视图。

我也遇到了同样的错误,所以我查看了Robotium的源代码,看看它们如何处理这个问题。答案是他们使用一些方法等待所需的时间。

对于片段,您可以在执行断言之前使用类似以下的内容:

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;
    }

我使用了5000毫秒的超时时间,看起来效果不错。

因此,在您的代码中,您应该替换

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

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

编辑:这个回答假设你的junit扩展了ActivityInstrumentationTestCase2<T>


谢谢回复。很有道理,但它并没有解决空指针的问题。 - HGPB
似乎我无法访问getView() - HGPB
奇怪,因为在我的项目中我必须使用它否则会得到 null。 - tbruyelle
2
是的,但我的错误在于我的ActivityWelcome默认加载了该片段,因此它已经存在。这意味着片段的创建(newInstance)代码块在setUp()中不是必需的(我混淆了)。实际上,在这种特定情况下,我并不想加载一个“单独”的片段进行测试。完全是我对ActivityInstrumentationTestCase2工作方式的误解。感谢您的时间。最终成功了! - HGPB
我添加了额外的Thread.sleep(20)来避免过于频繁地调用findFragmentByTag。 - wkarl
显示剩余4条评论

4

对于一个ActivityUnitTestCase测试,我需要在waitForFragment方法中添加以下代码:

// haven't really checked if this is necessary
getInstrumentation().waitForIdleSync();
// without this, waitForFragment() failed to find the fragment
getActivity().getFragmentManager().executePendingTransactions();

谢谢您澄清这一点。@tbruyelle的答案对我没有用。我已经检查过waitForIdleSync()调用并不是真正必要的。 - kazbeel
mFragment.getView() 不为 null 了吗? - Muhammad Babar
使用getSupportFragmentManager().executePendingT...在ActivityUnitTestCase中可以正常工作,因为我已经通过调用getSupportFragmentManager()添加了fragment。希望这能帮助到某个人。 - flobacca
澄清一下:实际上,我从未让Fragment调用onActivityCreated方法,但我确实通过findFragmentByTag()方法使Fragment不为空。 - flobacca

1
您可以使用来自'com.jayway.android.robotium:robotium-solo:5.2.1'的com.robotium.solo.Solo。
    mInstrumentation = InstrumentationRegistry.getInstrumentation();
    mSolo = new Solo(mInstrumentation);
    mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    .....
    mSolo.waitForFragmentById();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接