Поскольку этот вопрос и ответы помогли мне через несколько лет, я подумал, что добавлю свое собственное предложение, которое будет состоять в том, чтобы assert
чтобы dataPosition()
в конце чтения было таким же, как в конце записи. Опираясь на ответ 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());
}
Предыстория: это пришло ко мне после того, как я потратил (постыдное) количество времени на отладку плохого Parcelable
. В моем случае writeToParcel
записывал повторяющееся поле из одного объекта в умеренно сложном графе объектов. Поэтому последующие объекты считывались неправильно, приводя к вводящим в заблуждение исключениям, и не возникало ошибок в тестах с конкретным некорректно работающим объектом.
Это было мучительно, но потом я понял, что проверка dataPosition
помогла бы выявить проблему быстрее, поскольку у меня есть тесты на внутренних объектах, а также на основном контейнере.
Kotlin: Поскольку я работаю в Kotlin, немного лямбды и магии овеществления:
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
}
Теперь я могу очень легко проверить эти строки, если есть полный и надежный equals()
:
testObject.parcel.test { assertEquals(testObject, it) }
Обратите внимание, что .parcel.test
позволяет избежать повторного указания параметра универсального типа, используя этот ответ.
Или, для более сложных утверждений:
testObject.parcel.test {
assertEquals(123, it.id)
assertEquals("dewey", it.name)
// ...
}
person
dewey
schedule
10.01.2018