Comment testez-vous Parcelable? J'ai créé une classe Parcelable et écrit ce test unitaire
TestClass test = new TestClass();
Bundle bundle = new Bundle();
bundle.putParcelable("test", test);
TestClass testAfter = bundle.getParcelable("test");
assertEquals(testAfter.getStuff(), event1.getStuff());
J'essaie délibérément d'échouer au test en retournant null dans createFromParcel()
, mais il semble réussir. Il semble que le colis ne soit pas fragmenté tant que ce n’est pas nécessaire. Comment puis-je forcer le Bundle à ... grouper?
J'ai trouvé ce lien qui montre comment tester à la pièce un objet pouvant être parcellisé: http://stuffikeepforgettinghowtodo.blogspot.nl/2009/02/unit-test-your-custom-parcelable.html
Vous pouvez réellement sauter la Bundle
si vous n'avez pas vraiment besoin de l'inclure, comme l'a suggéré zorch. Vous obtiendrez alors quelque chose comme ceci:
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);
}
Vous pouvez le faire de cette manière:
//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));
Comme cette question et les réponses m'ont aidé plusieurs années sur toute la ligne, j'ai pensé ajouter ma propre suggestion, à savoir assert
que la dataPosition()
à la fin de la lecture était la même qu'à la fin de l'écriture. S'appuyant sur La réponse de Xilconic :
@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());
}
Arrière-plan: Cela m'est venu après avoir passé un temps (embarrassant) à déboguer un mauvais Parcelable
name__. Dans mon cas, writeToParcel
était en train d'écrire un champ en double à partir d'un objet dans un graphe d'objet moyennement complexe. Par conséquent, les objets subséquents ont été lus de manière incorrecte, avec des exceptions trompeuses et aucune erreur lors des tests avec l’objet spécifique se comportant mal.
J'ai eu du mal à retrouver la trace, puis j'ai réalisé que vérifier dataPosition
aurait permis de localiser le problème plus rapidement, car j'ai des tests sur les objets internes ainsi que sur le conteneur principal.
Kotlin: Depuis que je travaille à Kotlin, un peu de magie lambda et réifiante:
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
}
Je peux maintenant tester très facilement dans ce sens, s’il existe une equals()
complète et fiable:
testObject.parcel.test { assertEquals(testObject, it) }
Notez que le .parcel.test
évite de devoir spécifier à nouveau le paramètre de type générique en utilisant cette réponse .
Ou, pour des assertions plus complexes:
testObject.parcel.test {
assertEquals(123, it.id)
assertEquals("dewey", it.name)
// ...
}
J'utilise une classe d'assistance de parcelle pour convertir un objet en/à partir de parcelle.
Voir cet article: https://Gist.github.com/scallacs/f749a7385bcf75829a98d7b651efd02e
L'utilisation est très simple:
Model model = new Model("HelloWorld");
// Create an object from the parcel model
Model createdFromParcel = ParcelTestHelper.createFromParcel(model, model.CREATOR);
// Do your assertions...
assertEquals(model.value, createdFromParcel.value);
La mise en oeuvre:
import Android.os.Parcel;
import Android.os.Parcelable;
public class ParcelTestHelper {
public static String DEFAULT_CREATOR_FIELD = "CREATOR";
public static <T extends Parcelable> T createFromParcel(T input, Parcelable.Creator<T> creator) {
Parcel parcel = toParcel(input);
return fromParcel(parcel, creator);
}
public static <T extends Parcelable> T createFromParcel(T input) throws NoSuchFieldException, IllegalAccessException {
return createFromParcel(input, getCreator(input));
}
public static <T extends Parcelable> Parcel toParcel(T input) {
Parcel parcel = Parcel.obtain();
input.writeToParcel(parcel, input.describeContents());
parcel.setDataPosition(0);
return parcel;
}
public static <T> Parcelable.Creator<T> getCreator(T input) throws NoSuchFieldException, IllegalAccessException {
return getCreator(input, DEFAULT_CREATOR_FIELD);
}
public static <T> Parcelable.Creator<T> getCreator(T input, String field) throws NoSuchFieldException, IllegalAccessException {
Object creator = input.getClass().getField(field).get(input);
if (!(creator instanceof Parcelable.Creator)) {
throw new InternalError("Should have field " + field + " instance of Parcelable.Creator");
}
return (Parcelable.Creator<T>) creator;
}
public static <T extends Parcelable> T fromParcel(Parcel parcel, Parcelable.Creator<T> creator) {
return creator.createFromParcel(parcel);
}
}