6

Ho letto molti link da qui, blog github e robolectric ma non ho ancora trovato una soluzione funzionante (già usando Robolectric 2.0 alpha 2).Robolectric: Come posso testare un'attività che contiene un SherlockFragment?

UPDATE: Il problema si verifica anche se sostituiamo SherlockFragment per android.support.v4.app.Fragment.

sono stato in grado di testare uno SherlockFragmentActivity dopo aver seguito questo tip, ma quando aggiungo questo frammento, che è uno SherlockFragment, alla mia attività xml:

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

La classe 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); 
    } 
} 

E questo è il layout che viene gonfiato dal frammento:

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

ottengo il seguente errore:

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) 

Questa è la classe di test che sto usando:

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

L'applicazione sta lavorando bene sul dispositivo.

Cosa mi manca qui?

ps: Il codice sorgente completo è disponibile sul github

Edit: testato anche con il codice dalla piazza/master (2.0 alpha 3 quadrato 5) ramo e ha lo stesso problema. Controllare il LayoutBuilder.constructFragment, penso che il problema sia che activity.getSupportFragmentManager().beginTransaction().add(fragment, tag).commit() non funziona con SherlockFragment, quindi fragment.getView() restituisce null.

Non sono sicuro di poter fare qualsiasi cosa al mio fianco per risolvere il problema ... Sto già controllando se posso sistemarlo sul lato di robolectric, per favore fatemi sapere se qualcuno ha qualche consiglio su questo.

risposta

7

Si potrebbe provare a utilizzare nuovi ActivityController Robolectric 2.0, che risolve alcuni problemi di programmazione/fine-di-operazioni che spesso affiorano.

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

Consente di sospendere temporaneamente il looper principale durante la chiamata a onCreate().

+1

Ciao @Xian, grazie per la risposta. Ho appena testato con 2.0-rc1 e 2.0-rc2-SNAPSHOT. Ancora ottenere un NPE java.lang.NullPointerException: null \t a android.view.ViewGroup.addView (ViewGroup.java:3187) \t a android.view.ViewGroup.addView (ViewGroup.java:3170) \t a org .robolectric.res.builder.LayoutBuilder.constructFragment (LayoutBuilder.java:150) – marcelopazzo

+0

Inserito il codice aggiornato in [github] (https://github.com/marcelopazzo/RobolectricSample). Inoltre ho scoperto che questo non è collegato a ActionBarSherlock, sto ricevendo gli stessi errori usando android.support.v4.app.Fragment. – marcelopazzo

+0

Il problema è stato risolto su robolectric 2.1 – marcelopazzo

0

io non sono contento di questa soluzione, ma c'è un modo per farlo funzionare:

Il metodo fragment.getView() sta tornando nulla perché il onCreateView dal mio frammento è stato mai chiamato. Dovrebbe essere chiamato con il metodo moveToState da android.support.v4.app.FragmentManager, ma non perché f.mFromLayout era falso.

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

Quindi, se si aggiunge questo blocco di codice ai tuoi frammenti onCreate metodo, che funzionerà.

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

come ho detto, non è una vera soluzione, ma un modo per farlo funzionare prima che qualcuno trova una soluzione adeguata.

[UPDATE] Questo metodo non funziona con Robolectric 2.0 Final

3

Calling

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

chiamerà il metodo Fragment.onCreateView

+0

Grazie per il suggerimento. Ho provato diverse combinazioni delle chiamate iniziali (ref: http://robolectric.org/activity-lifecycle/) e questo è il set minimo che ha funzionato per il mio caso: .create(). Visible(). Start(). Get(); Precedentemente ho usato solo .create(). Visible(). Get() e le viste sui frammenti non sono state create. Robolectric 3.0. –

Problemi correlati