Skip to content

Instantly share code, notes, and snippets.

@tomaszpolanski
Last active June 28, 2022 21:04
Show Gist options
  • Save tomaszpolanski/92a2eada1e06e4a4c71abb298d397173 to your computer and use it in GitHub Desktop.
Save tomaszpolanski/92a2eada1e06e4a4c71abb298d397173 to your computer and use it in GitHub Desktop.
Parcelize testing
import android.annotation.SuppressLint
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@SuppressLint("ParcelCreator") // IntelliJ Issue https://youtrack.jetbrains.com/issue/KT-19300
@Parcelize
data class Movie(val title: String) : Parcelable
import android.os.Parcel
import android.support.test.runner.AndroidJUnit4
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MovieTest {
@Test
fun verify_parceling() {
val movie = Movie("Infinity War")
movie.testParcel()
.apply {
assertThat(this).isEqualTo(movie)
assertThat(this).isNotSameAs(movie)
}
}
}
import android.os.Bundle
import android.os.Parcel
import android.os.Parcelable
inline fun <reified R : Parcelable> R.testParcel(): R {
val bytes = marshallParcelable(this)
return unmarshallParcelable(bytes)
}
inline fun <reified R : Parcelable> marshallParcelable(parcelable: R): ByteArray {
val bundle = Bundle().apply { putParcelable(R::class.java.name, parcelable) }
return marshall(bundle)
}
fun marshall(bundle: Bundle): ByteArray =
Parcel.obtain().use {
it.writeBundle(bundle)
it.marshall()
}
inline fun <reified R : Parcelable> unmarshallParcelable(bytes: ByteArray): R = unmarshall(bytes)
.readBundle()
.run {
classLoader = R::class.java.classLoader
getParcelable(R::class.java.name)
}
fun unmarshall(bytes: ByteArray): Parcel =
Parcel.obtain().apply {
unmarshall(bytes, 0, bytes.size)
setDataPosition(0)
}
private fun <T> Parcel.use(block: (Parcel) -> T): T =
try {
block(this)
} finally {
this.recycle()
}
@tomaszpolanski
Copy link
Author

Last thing, what kotlin version are you using?

@mregnauld
Copy link

1.6.21

@tomaszpolanski
Copy link
Author

The last last thing, is there a reason why you are not using https://developer.android.com/kotlin/parcelize ?
This solution was used before parcelize

@mregnauld
Copy link

mregnauld commented Jun 22, 2022

I use parcelize, but I wanted to unit test a quite tricky use case, where one of the attribute of my parcelable object is of type Any, so I have to to the write(parcel: Parcel, flags: Int) and the create(parcel: Parcel) by myself.

@tomaszpolanski
Copy link
Author

Those two approaches do the same thing in a different way, therefore UT your prod code using this approach would actually not test the same functionality.
Did you consider using epresso tests for your current implementation?

@mregnauld
Copy link

I can only use pure unit test, since I'm working on a Flutter project (so there is no integration testing available, therefore I can't use Espresso).
But that's ok, I'll find another way, thanks.

@tomaszpolanski
Copy link
Author

I also work with flutter and you can write Espresso tests there. You can check out this link

@mregnauld
Copy link

Oh cool, I didn't know, thanks for the link!

@SimonMarquis
Copy link

The issue comes from getParcelable now correctly being annotated with @Nullable.
You can update the unmarshallParcelable return type to R? to fix this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment