Skip to content

Instantly share code, notes, and snippets.

@Zellius
Last active March 19, 2017 17:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zellius/30053ca89e05c285d05ff4a1fdf25ec6 to your computer and use it in GitHub Desktop.
Save Zellius/30053ca89e05c285d05ff4a1fdf25ec6 to your computer and use it in GitHub Desktop.
How to test parcelables
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