Last active
March 19, 2017 17:36
-
-
Save Zellius/30053ca89e05c285d05ff4a1fdf25ec6 to your computer and use it in GitHub Desktop.
How to test parcelables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ru.solodovnikov.parcelabletest | |
import android.os.Parcel | |
import android.os.Parcelable | |
import io.github.benas.randombeans.EnhancedRandomBuilder | |
import io.github.benas.randombeans.api.Randomizer | |
import org.junit.Assert | |
import org.junit.Test | |
import org.junit.runner.RunWith | |
import org.mockito.Mockito | |
import org.reflections.Reflections | |
import org.robolectric.RobolectricTestRunner | |
import java.io.Serializable | |
import java.lang.reflect.Modifier | |
import java.lang.reflect.ParameterizedType | |
import java.lang.reflect.WildcardType | |
@RunWith(RobolectricTestRunner::class) | |
class ParcelableTest { | |
private val packageName = javaClass.`package`.name | |
private val random = EnhancedRandomBuilder.aNewEnhancedRandomBuilder().build() | |
@Test | |
fun testVoParcelables() { | |
val reflections = Reflections("$packageName.entity") | |
//get all parcelable classes in the package | |
val parcelables = reflections.getSubTypesOf(Parcelable::class.java) | |
//remove any abstract class | |
parcelables.filter { !Modifier.isAbstract(it.modifiers) } | |
.forEach { | |
//random instance | |
val parcelableVoInstance = random.nextObject(it) | |
//creator of the instance | |
val parcelableVoCreator = getParcelableCreator(it) | |
testParcelable(parcelableVoInstance, parcelableVoCreator) | |
} | |
} | |
private fun getParcelableCreator(clazz: Class<out Parcelable>): Parcelable.Creator<out Parcelable> { | |
val creatorField = clazz.getField("CREATOR") | |
return creatorField.get(null) as Parcelable.Creator<Parcelable> | |
} | |
private fun testParcelable(parcelable: Parcelable, creator: Parcelable.Creator<out Parcelable>) { | |
val flags = 0 | |
val parcel = Mockito.spy(Parcel.obtain()) | |
parcelable.writeToParcel(parcel, flags) | |
val inOrder = Mockito.inOrder(parcel) | |
//check that all write methods was called in the correct order | |
parcelable.javaClass.declaredFields.forEach { field -> | |
field.isAccessible = true | |
if (field.type.isAssignableFrom(String::class.java)) { | |
inOrder.verify(parcel).writeString(field.get(parcelable) as String) | |
} else if (field.type.isAssignableFrom(Int::class.java)) { | |
inOrder.verify(parcel).writeInt(field.get(parcelable) as Int) | |
} else if (field.type.isAssignableFrom(Long::class.java)) { | |
inOrder.verify(parcel).writeLong(field.get(parcelable) as Long) | |
} else if (field.type.isAssignableFrom(Double::class.java)) { | |
inOrder.verify(parcel).writeDouble(field.get(parcelable) as Double) | |
} else if (field.type.isAssignableFrom(Boolean::class.java)) { | |
inOrder.verify(parcel).writeByte(if (field.get(parcelable) as Boolean) 1 else 0) | |
} else if (field.type.interfaces.contains(Parcelable::class.java)) { | |
inOrder.verify(parcel).writeParcelableCompat(field.get(parcelable) as Parcelable, flags) | |
} else if (field.type.isAssignableFrom(List::class.java)) { | |
if ((((field.genericType as ParameterizedType).actualTypeArguments[0] as WildcardType).upperBounds[0] as Class<*>).interfaces.contains(Parcelable::class.java)) { | |
inOrder.verify(parcel).writeTypedList(field.get(parcelable) as List<Parcelable>) | |
} else { | |
inOrder.verify(parcel).writeList(field.get(parcelable) as List<*>) | |
} | |
} else if (field.type.isAssignableFrom(Serializable::class.java)) { | |
inOrder.verify(parcel).writeSerializable((field.get(parcelable) as Serializable)) | |
} | |
// add other types | |
} | |
parcel.setDataPosition(0) | |
val readiedParcelable = creator.createFromParcel(parcel) | |
//check that all fields are equals | |
assertFields(parcelable, readiedParcelable) | |
} | |
private fun assertFields(expected: Any, actual: Any) { | |
val expectedFields = expected.javaClass.declaredFields | |
val actualFields = actual.javaClass.declaredFields | |
expectedFields.forEachIndexed { i, field -> | |
field.isAccessible = true | |
val expectedParam = field.get(expected) | |
actualFields[i].isAccessible = true | |
val resultParam = actualFields[i].get(actual) | |
if (field.type.name.startsWith(packageName)) { | |
assertFields(expectedParam, resultParam) | |
} else { | |
Assert.assertEquals("Class: ${expected.javaClass.simpleName}, field: ${field.name}", expectedParam, resultParam) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment