6

Czytałem dużo linków stąd, Github i Robolectric Blog, ale nie mogłem znaleźć jeszcze działającego rozwiązania (już korzystam z Robolectric 2.0 alpha 2).Robolectric: Jak mogę przetestować działanie zawierające SherlockFragment?

UPDATE: Problem zdarza się również, nawet jeśli wymienimy SherlockFragment dla android.support.v4.app.Fragment.

udało mi się przetestować SherlockFragmentActivity po wykonaniu tej tip, ale kiedy dodać ten fragment, który jest SherlockFragment, do mojej działalności xml:

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

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

To jest układ nadawany przez 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> 

pojawia się następujący błąd:

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) 

Jest to klasa test, który używam:

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

Aplikacja działa poprawnie na urządzeniu.

Czego mi tu brakuje?

PS: pełny kod źródłowy jest dostępny na github

Edycja: testowany również kodem od placu/Master (2,0 alfa 3 kwadratowy 5) oddział otrzymał ten sam problem. Sprawdzanie LayoutBuilder.constructFragment, myślę, że problem polega na tym, że activity.getSupportFragmentManager().beginTransaction().add(fragment, tag).commit() nie działa z SherlockFragment, więc fragment.getView() zwraca zero.

Nie jestem pewien, czy mogę zrobić coś po mojej stronie, aby to naprawić ... Już sprawdzam, czy mogę to naprawić po stronie robolectric, proszę dać mi znać, jeśli ktoś ma jakąkolwiek wskazówkę na ten temat.

Odpowiedz

7

Można spróbować użyć Robolectric 2.0 nowego ActivityController, który naprawia kilka harmonogramów/order-of-operacjach problemy, które często pojawiają się.

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

Ułatwia tymczasowe wstrzymanie głównego programu sprzęgającego podczas wywołania onCreate().

+1

Hi @Xian, dzięki za odpowiedź. Właśnie testowałem z wersją 2.0-rc1 i 2.0-rc2-SNAPSHOT. Wciąż dostaję NPE java.lang.NullPointerException: null \t na android.view.ViewGroup.addView (ViewGroup.java:3187) \t na android.view.ViewGroup.addView (ViewGroup.java:3170) \t w org .robolectric.res.builder.LayoutBuilder.constructFragment (LayoutBuilder.java:150) – marcelopazzo

+0

Pchnął zaktualizowany kod na [github] (https://github.com/marcelopazzo/RobolectricSample). Również okazało się, że nie jest to związane z ActionBarSherlock, otrzymuję te same błędy przy użyciu android.support.v4.app.Fragment. – marcelopazzo

+0

Problem został naprawiony na robolectric 2.1 – marcelopazzo

0

nie jestem zadowolony z tego rozwiązania, ale istnieje sposób, aby to działało:

Sposób fragment.getView() zwraca wartość null, ponieważ onCreateView z mojego Fragment nigdy nie został powołany. Powinien zostać wywołany metodą moveToState od android.support.v4.app.FragmentManager, ale nie dlatego, że f.mFromLayout był fałszywy.

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

Tak więc, jeśli dodać ten fragment kodu do fragmentów onCreate metodę, to będzie działać.

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

Tak jak powiedziałem, nie jest to prawdziwe rozwiązanie, ale sposób na sprawdzenie, zanim ktoś znajdzie właściwe rozwiązanie.

[UPDATE] Ta metoda nie zadziała z Robolectric 2,0 Końcowego

3

Wywołanie

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

wezwie metoda Fragment.onCreateView

+0

Dzięki za napiwek. Próbowałem różnych kombinacji początkowych wywołań (patrz: http://robolectric.org/activity-lifecycle/) i jest to minimalny zestaw, który zadziałał w moim przypadku: .create(). Visible(). Start().(); Poprzednio użyłem tylko .create(). Visible(). Get(), a widoki na fragmenty nie zostały utworzone. Robolectric 3.0. –