Skip to content

Instantly share code, notes, and snippets.

@tomaszpolanski
Last active June 28, 2022 21:04
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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()
}
@twogood
Copy link

twogood commented Dec 7, 2019

Thanks mate!

@tomaszpolanski
Copy link
Author

Thanks mate!

Your welcome. Just remember that withing last 2 years the kotlin's @Parcelize really improved stability.
I would recommend only testing the most crucial (and complex) parcels in your project as with more basic there shouldn't be any issue.

@mregnauld
Copy link

I have a probe with unmarshallParcelable(), I get the following error:

Type mismatch.
Required: R
Found: Nothing?

How can I fix that?
Thanks.

@tomaszpolanski
Copy link
Author

Nothing? is a strange type to have. This type should not be serializable. Do you have in your parcel Nothing? type?

@mregnauld
Copy link

mregnauld commented Jun 22, 2022

No I don't.
It happens in Android Studio when I copy/paste utils.kt in the test folder.
Does it only work in the androidTest folder, then?

@tomaszpolanski
Copy link
Author

It should work everywhere. The last time I've used the code was 2 years ago and kotlin changes most likely has changed it.
Could you include the whole stacktrace?

@mregnauld
Copy link

Again, that's all I have, no stack trace, it appears on Android Studio right after a copy/paste of that class.

@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