6

我一直在阅读这里、github 和 robolectric 博客的很多链接,但还没有找到可行的解决方案(已经使用 Robolectric 2.0 alpha 2)。

更新:即使我们替换SherlockFragmentandroid.support.v4.app.Fragment.

遵循此提示后,我能够测试 SherlockFragmentActivity ,但是当我将此片段(即 SherlockFragment)添加到我的活动 xml 时:

<fragment 
    android:name="com.marcelopazzo.fragmentapplication.ExampleFragment" 
    android:id="@+id/example_fragment"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" />

SherlockFragment 类:

public class ExampleFragment extends SherlockFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

这是被片段夸大的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/hello_again"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_again" />

</LinearLayout>

我收到以下错误:

java.lang.NullPointerException
    at org.robolectric.shadows.ShadowViewGroup.addView(ShadowViewGroup.java:69)
    at android.view.ViewGroup.addView(ViewGroup.java)
    at org.robolectric.res.builder.LayoutBuilder.constructFragment(LayoutBuilder.java:150)
    at org.robolectric.res.builder.LayoutBuilder.create(LayoutBuilder.java:104)
    at org.robolectric.res.builder.LayoutBuilder.doInflate(LayoutBuilder.java:42)
    at org.robolectric.res.builder.LayoutBuilder.doInflate(LayoutBuilder.java:45)
    at org.robolectric.res.builder.LayoutBuilder.inflateView(LayoutBuilder.java:62)
    at org.robolectric.shadows.ShadowLayoutInflater.inflate(ShadowLayoutInflater.java:50)
    at org.robolectric.shadows.ShadowLayoutInflater.inflate(ShadowLayoutInflater.java:55)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at com.squareup.test.ActionBarSherlockRobolectric.setContentView(ActionBarSherlockRobolectric.java:38)
    at com.actionbarsherlock.app.SherlockFragmentActivity.setContentView(SherlockFragmentActivity.java:262)
    at com.marcelopazzo.fragmentapplication.MainActivity.onCreate(MainActivity.java:13)
    at com.marcelopazzo.fragmentapplication.MainActivityTest.setUp(MainActivityTest.java:33)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:110)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:234)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:133)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:114)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:188)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:166)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:86)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:101)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)

这是我正在使用的测试类:

@RunWith(RobolectricTestRunner.class)
public class MainActivityTest {

    private MainActivity activity;
    private TextView textView;

    public static final String GREETINGS = "Hello world!";  

    @Before
    public void setUp() {

        ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class);
        ActionBarSherlock.unregisterImplementation(ActionBarSherlockNative.class);
        ActionBarSherlock.unregisterImplementation(ActionBarSherlockCompat.class);

        activity = new MainActivity();
        activity.onCreate(null);

        textView = (TextView) activity.findViewById(R.id.hello);
    }

    @Test
    public void shouldGreet() {
        assertEquals(GREETINGS, textView.getText());
    }
}

该应用程序在设备上运行良好。

我在这里想念什么?

ps:完整的源码在github上

编辑:还使用 square/master (2.0 alpha 3 square 5) 分支的代码进行了测试,并遇到了同样的问题。检查LayoutBuilder.constructFragment,我认为问题在于activity.getSupportFragmentManager().beginTransaction().add(fragment, tag).commit()不与 SherlockFragment 一起使用,因此fragment.getView()返回 null。

我不确定我是否可以做任何事情来解决这个问题......我已经在检查我是否可以在 robolectric 方面解决它,如果有人对此有任何提示,请告诉我。

4

3 回答 3

7

您可以尝试使用 Robolectric 2.0 的新 ActivityController,它修复了一些经常出现的调度/操作顺序问题。

MainActivity activity = Robolectric.buildActivity(MainActivity.class)
                                    .create().get();

它安排主循环器在调用 onCreate() 期间暂时暂停。

于 2013-05-11T00:42:46.943 回答
3

打电话

Robolectric.buildActivity(YourActivityClass.class).attach().create().start().resume().get();

将调用您的 Fragment.onCreateView 方法

于 2013-07-30T11:55:12.743 回答
0

我对这个解决方案不满意,但有一种方法可以让它发挥作用:

该方法fragment.getView()返回 null 因为onCreateView我的 Fragment 从未调用过。它应该由moveToStatefrom的方法调用android.support.v4.app.FragmentManager,但不是因为f.mFromLayout是假的。

f.mActivity = mActivity;
f.mFragmentManager = mActivity.mFragments;
f.mCalled = false;
f.onAttach(mActivity);
if (!f.mCalled) {
    throw new SuperNotCalledException("Fragment " + f
    + " did not call through to super.onAttach()");
}
mActivity.onAttachFragment(f);

if (!f.mRetaining) {
    f.mCalled = false;
    f.onCreate(f.mSavedFragmentState);
    if (!f.mCalled) {
        throw new SuperNotCalledException("Fragment " + f
        + " did not call through to super.onCreate()");
    }
}
f.mRetaining = false;
if (f.mFromLayout) {
    // For fragments that are part of the content view
    // layout, we need to instantiate the view immediately
    // and the inflater will take care of adding it.
    f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
    null, f.mSavedFragmentState);
    if (f.mView != null) {
    f.mInnerView = f.mView;
    f.mView = NoSaveStateFrameLayout.wrap(f.mView);
    if (f.mHidden) f.mView.setVisibility(View.GONE);
        f.onViewCreated(f.mView, f.mSavedFragmentState);
    } else {
        f.mInnerView = null;
    }
}

因此,如果您将此代码块添加到您的片段onCreate方法中,它将起作用。

Field field = Fragment.class.getDeclaredField("mFromLayout");
field.setAccessible(true);
field.setBoolean(this, true);
field.setAccessible(false);

正如我所说,这不是一个真正的解决方案,而是一种在有人找到合适的解决方案之前让它发挥作用的方法。

[更新] 此方法不适用于 Robolectric 2.0 Final

于 2013-04-25T18:36:23.867 回答