2012-10-10 12 views
28

Come si esegue il test di unità Parcelable? Ho creato una classe Parcelable, e scritto questo test di unitàTest unità Android: Bundle/Parcelable

TestClass test = new TestClass(); 
Bundle bundle = new Bundle(); 
bundle.putParcelable("test", test); 

TestClass testAfter = bundle.getParcelable("test"); 
assertEquals(testAfter.getStuff(), event1.getStuff()); 

ho volutamente provo a fallire il test restituendo null nel createFromParcel(), ma sembra avere successo. Sembra che non venga parcellizzato finché non è necessario. Come impone il bundle a..bundle?

+1

Se uno dei nostri anwers come soluzione al vostro problema, si prega di contrassegnare come risposta accettata :) – Xilconic

risposta

81

ho trovato questo link che mostra come è possibile unit test un oggetto Parcelable: http://stuffikeepforgettinghowtodo.blogspot.nl/2009/02/unit-test-your-custom-parcelable.html

Si può effettivamente saltare la Bundle se don Ho davvero bisogno di includerlo come zorch ha fatto il suo suggerimento. Si potrebbe quindi ottenere qualcosa del genere:

public void testTestClassParcelable(){ 
    TestClass test = new TestClass(); 

    // Obtain a Parcel object and write the parcelable object to it: 
    Parcel parcel = Parcel.obtain(); 
    test.writeToParcel(parcel, 0); 

    // After you're done with writing, you need to reset the parcel for reading: 
    parcel.setDataPosition(0); 

    // Reconstruct object from parcel and asserts: 
    TestClass createdFromParcel = TestClass.CREATOR.createFromParcel(parcel); 
    assertEquals(test, createdFromParcel); 
} 
+3

'parcel.setDataPosition (0);' era il segreto. Grazie – scorpiodawg

+0

Funziona anche per me. Grazie!. – ernestkamara

+0

Non ha possibilità di lavorare! Otterrai sempre '' 'BadParcelableException'''. – ddmytrenko

16

Si può fare in questo modo:

//Create parcelable object and put to Bundle 
    Question q = new Question(questionId, surveyServerId, title, type, answers); 
    Bundle b = new Bundle(); 
    b.putParcelable("someTag", q); 

//Save bundle to parcel 
    Parcel parcel = Parcel.obtain(); 
    b.writeToParcel(parcel, 0); 

//Extract bundle from parcel 
    parcel.setDataPosition(0); 
    Bundle b2 = parcel.readBundle(); 
    b2.setClassLoader(Question.class.getClassLoader()); 
    Question q2 = b2.getParcelable("someTag"); 

//Check that objects are not same and test that objects are equal 
    assertFalse("Bundle is the same", b2 == b); 
    assertFalse("Question is the same", q2 == q); 
    assertTrue("Questions aren't equal", q2.equals(q)); 
+0

Hai provato con questo tipo di asserzione: 'Assert .assertTrue (EqualsBuilder.reflectionEquals (q2, q)); '? Chiedo perché nel caso in cui tu abbia un 'Elenco = nuovo ArrayList ' come un campo nel tuo modello di dati 'Question.java', allora il codice che hai scritto non funziona.Se hai 'ArrayList = new ArrayList ' funziona. Sai come aggiustarlo? –

1

Dal momento che questa domanda e le risposte mi ha aiutato diversi anni giù la linea, ho pensato di aggiungere la mia proposta, che sarebbe quello di assert che il dataPosition() alla fine del la lettura era la stessa della fine della scrittura. Sulla Xilconic's answer:

@Test 
public void testTestClassParcelable(){ 
    TestClass test = new TestClass(); 

    // Obtain a Parcel object and write the parcelable object to it: 
    Parcel parcel = Parcel.obtain(); 
    test.writeToParcel(parcel, 0); 

    //>>>>> Record dataPosition 
    int eop = parcel.dataPosition(); 

    // After you're done with writing, you need to reset the parcel for reading: 
    parcel.setDataPosition(0); 

    // Reconstruct object from parcel and asserts: 
    TestClass createdFromParcel = TestClass.CREATOR.createFromParcel(parcel); 
    assertEquals(test, createdFromParcel); 

    //>>>>> Verify dataPosition 
    assertEquals(eop, parcel.dataPosition()); 
} 

Background: Questo è venuto da me dopo aver trascorso un importo (imbarazzante) di tempo debug di un cattivo Parcelable. Nel mio caso, writeToParcel stava scrivendo un campo duplicato da un oggetto all'interno di un grafico di oggetto moderatamente complesso. Pertanto gli oggetti successivi a sono stati letti in modo errato, fornendo eccezioni fuorvianti e nessun errore nei test con l'oggetto specifico che si comporta male.

E 'stato un dolore da rintracciare, e poi mi sono reso conto che il controllo di dataPosition avrebbe individuato il problema più velocemente poiché ho eseguito test su oggetti interni e sul contenitore principale.


Kotlin: Dal momento che sto lavorando in Kotlin, un po 'di lambda e magia reificare:

class ParcelWrap<T>(val value: T) 

val <T> T.parcel: ParcelWrap<T> get() = ParcelWrap(this) 

inline fun <reified T: Parcelable> ParcelWrap<T>.test(
     flags: Int = 0, 
     classLoader: ClassLoader = T::class.java.classLoader, 
     checks: (T) -> Unit 
): T { 
    // Create the parcel 
    val parcel: Parcel = Parcel.obtain() 
    parcel.writeParcelable(this.value, flags) 

    // Record dataPosition 
    val eop = parcel.dataPosition() 

    // Reset the parcel 
    parcel.setDataPosition(0) 

    // Read from the parcel 
    val newObject = parcel.readParcelable<T>(classLoader) 

    // Perform the checks provided in the lambda 
    checks(newObject) 

    // Verify dataPosition 
    assertEquals("writeToParcel wrote too much data or read didn't finish reading", eop, parcel.dataPosition()) 
    return newObject 
} 

ora posso test molto facilmente in questo senso, se v'è un completo ed affidabile equals() :

testObject.parcel.test { assertEquals(testObject, it) } 

Annotare il .parcel.test evita di dover specificare nuovamente parametro di tipo generico utilizzando 012.324.924,439 mila.

Oppure, per ulteriori asserzioni complesse:

testObject.parcel.test { 
    assertEquals(123, it.id) 
    assertEquals("dewey", it.name) 
    // ... 
}