Robolectric: How can I check the activity containing SherlockFragment?

I read a lot of links from here, github and robolectric blog, but have not yet found a working solution (already using Robolectric 2.0 alpha 2).

UPDATE: The problem also occurs even if we replace SherlockFragment with android.support.v4.app.Fragment .

I managed to test SherlockFragmentActivity after this tip , but when I add this fragment, i.e. SherlockFragment, to my xml activity

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

SherlockFragment Class:

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

And this is a layout that inflates with a fragment:

 <?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> 

I get the following error:

 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) 

This is the testing class I'm using:

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

The application works fine on the device.

What am I missing here?

ps: Full source code available on github

Edit: also checked with code from the square / lead (2.0 alpha 3 square 5) branches and got the same problem. LayoutBuilder.constructFragment checking LayoutBuilder.constructFragment , I think the problem is that activity.getSupportFragmentManager().beginTransaction().add(fragment, tag).commit() does not work with SherlockFragment, so fragment.getView() returns null.

I'm not sure if I can do anything on my side to fix it ... I already check if I can fix it on the side of the rober, please let me know if anyone has any advice on this .

+6
source share
3 answers

You can try using Robolectric 2.0 new ActivityController, which fixes some scheduling / ordering problems that often occur.

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

Sets the main looper to temporarily pause during an onCreate () call.

+7
source

Call

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

will call your Fragment.onCreateView method

+3
source

I am not happy with this solution, but there is a way to make it work:

The fragment.getView() method returns null because onCreateView from my fragment has never been called. It should be called by the moveToState method from android.support.v4.app.FragmentManager , but not because f.mFromLayout was false.

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

So, if you add this code block to your onCreate snippets onCreate , it will work.

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

As I said, this is not a real solution, but a way to make it work before someone finds a suitable solution.

[UPDATE] This method will not work with Robolectric 2.0 Final

0
source

Source: https://habr.com/ru/post/943484/


All Articles