6

ここ、github、robolectric ブログから多くのリンクを読んでいますが、まだ実用的な解決策を見つけることができませんでした (既に Robolectric 2.0 alpha 2 を使用しています)。

更新:SherlockFragment forを置き換えても問題は発生しandroid.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) ブランチのコードでもテストされ、同じ問題が発生しました。を確認すると、問題はSherlockFragment で動作していないため、null が返されLayoutBuilder.constructFragmentていることだと思います。activity.getSupportFragmentManager().beginTransaction().add(fragment, tag).commit()fragment.getView()

これを修正するために自分の側で何かできるかどうかはわかりません... robolectric の側で修正できるかどうかはすでに確認しています。これに関するヒントがあれば教えてください。

4

3 に答える 3

7

Robolectric 2.0 の新しい ActivityController を使用してみてください。これにより、頻繁に発生するスケジューリング/操作順序の問題が修正されます。

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

onCreate() の呼び出し中に、メイン ルーパーが一時的に一時停止するように調整します。

于 2013-05-11T00:42:46.943 に答える
0

私はこの解決策に満足していませんが、それを機能させる方法があります:

from my Fragment が呼び出されなかったため、メソッドfragment.getView()は null を返しています。onCreateViewメソッドmoveToStatefromで呼び出す必要がありますが、 falseの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 に答える