Android单元测试:Bundle/Parcelable

gar*_*tor 29 android unit-testing bundle parcelable

你如何对Parcelable进行单元测试?我创建了一个Parcelable类,并编写了这个单元测试

TestClass test = new TestClass();
Bundle bundle = new Bundle();
bundle.putParcelable("test", test);

TestClass testAfter = bundle.getParcelable("test");
assertEquals(testAfter.getStuff(), event1.getStuff());
Run Code Online (Sandbox Code Playgroud)

我故意试图通过返回null来测试失败createFromParcel(),但它似乎成功了.它似乎在需要之前不会被包围.我该怎么强迫Bundle来...捆绑?

Xil*_*nic 86

我发现这个链接显示了如何对可以对象进行单元测试:http://stuffikeepforgettinghowtodo.blogspot.nl/2009/02/unit-test-your-custom-parcelable.html

你实际上可以跳过,Bundle如果你真的不需要包括它像zorch做他的建议.然后你会得到这样的东西:

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);

    // 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);
}
Run Code Online (Sandbox Code Playgroud)

  • `parcel.setDataPosition(0);`是秘密.谢谢 (5认同)
  • @ddmytrenko BadParcelableException当对象本身被不正确地瓜分发生.例如,当您的读写对象的顺序不同时 (2认同)

chi*_*kiv 17

你可以这样做:

//Create parcelable object and put to Bundle
    Question q = new Question(questionId, surveyServerId, title, type, answers);
    Bundle b = new Bundle();
    b.putParcelable("someTag", q);

//Save bundle to parcel
    Parcel parcel = Parcel.obtain();
    b.writeToParcel(parcel, 0);

//Extract bundle from parcel
    parcel.setDataPosition(0);
    Bundle b2 = parcel.readBundle();
    b2.setClassLoader(Question.class.getClassLoader());
    Question q2 = b2.getParcelable("someTag");

//Check that objects are not same and test that objects are equal
    assertFalse("Bundle is the same", b2 == b);
    assertFalse("Question is the same", q2 == q);
    assertTrue("Questions aren't equal", q2.equals(q));
Run Code Online (Sandbox Code Playgroud)


小智 6

因为这个问题和答案帮助了我好几年了线,我想我会添加自己的建议,这将是assertdataPosition()在读的结束是一样的写入结束。基于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());
}
Run Code Online (Sandbox Code Playgroud)

背景:这是在花了(令人尴尬的)大量时间调试一个糟糕的Parcelable. 在我的情况下,writeToParcel正在从一个中等复杂的对象图中的一个对象中编写一个重复的字段。因此,随后的对象被错误地读取,给出了误导性的异常,并且在使用特定行为异常的对象进行测试时没有错误。

追踪起来很痛苦,然后我意识到检查dataPosition可以更快地查明问题,因为我对内部对象和主容器进行了测试。


Kotlin:因为我在 Kotlin 工作,所以有点 lambda 和 reifying 魔法:

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
}
Run Code Online (Sandbox Code Playgroud)

我现在可以很容易地沿着这些方向测试,如果有一个完整和可靠的equals()

testObject.parcel.test { assertEquals(testObject, it) }
Run Code Online (Sandbox Code Playgroud)

请注意,.parcel.test避免使用此答案重新指定泛型类型参数。

或者,对于更复杂的断言:

testObject.parcel.test {
    assertEquals(123, it.id)
    assertEquals("dewey", it.name)
    // ...
}
Run Code Online (Sandbox Code Playgroud)