我正在开发一个 Android 应用程序(API 15),在尝试编写单元测试时遇到以下问题:
我使用 android.os.Parcel 保存一个类(例如,如果屏幕转动)并将其发送到另一个 Activity。如果我尝试像这样对包裹方法进行单元测试(我从互联网上得到这个):
@Test
public void testParcel() {
Comment test = new Comment();
test.setId(testNr0Id);
test.setComment(testNr0String);
// 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:
Comment createdFromParcel = Comment.CREATOR.createFromParcel(parcel);
assertEquals(test, createdFromParcel);
}
然后我得到一个 NullPointerException,因为从 Parcel.obtain() 返回的 Parcel 是 null。 JavaDoc 只是说这个方法“从池中返回一个包裹对象”。现在我的问题是:哪个池?为什么这个 Parcel-Object 为空?有什么建议如何进行此测试运行吗?
感谢您的帮助
迈克尔
我也遇到过同样的问题。然而,当我将测试从
test
目录移动到 androidTest
目录后,一切都开始正常工作。我认为这是因为 Parcel
类是系统一类,因此也需要对其进行检测。
避免完全使用 Robolectric 或仪器,例如如果您只想在不连接任何设备的情况下使用 JUnit,则可以使用 Mockito 来模拟 Parcel 内的所有内容。
我有一个简单的实现,并且在我的许多项目中使用它:
// Mockito is required for this to work
class ParcelFake {
companion object {
@JvmStatic fun obtain(): Parcel {
return ParcelFake().mock
}
}
private var position = 0
private var store = mutableListOf<Any>()
private var mock = mock<Parcel>()
init {
setupWrites()
setupReads()
setupOthers()
}
// uncomment when needed for the first time
private fun setupWrites() {
val answer = { i: InvocationOnMock ->
with(store) {
add(i.arguments[0])
get(lastIndex)
}
}
whenever(mock.writeByte(anyByte())).thenAnswer(answer)
whenever(mock.writeInt(anyInt())).thenAnswer(answer)
whenever(mock.writeString(anyString())).thenAnswer(answer)
// whenever(mock.writeLong(anyLong())).thenAnswer(answer)
// whenever(mock.writeFloat(anyFloat())).thenAnswer(answer)
// whenever(mock.writeDouble(anyDouble())).thenAnswer(answer)
}
// uncomment when needed for the first time
private fun setupReads() {
val answer = { _: InvocationOnMock -> store[position++] }
whenever(mock.readByte()).thenAnswer(answer)
whenever(mock.readInt()).thenAnswer(answer)
whenever(mock.readString()).thenAnswer(answer)
// whenever(mock.readLong()).thenAnswer(answer)
// whenever(mock.readFloat()).thenAnswer(answer)
// whenever(mock.readDouble()).thenAnswer(answer)
}
private fun setupOthers() {
val answer = { i: InvocationOnMock ->
position = i.arguments[0] as Int
null
}
whenever(mock.setDataPosition(anyInt()))
.thenAnswer(answer)
}
}
基本思想是拥有一个后备存储(即列表)并将所有内容推入其中 - 但您确实需要使用 Mockito 在内部模拟 Parcel 才能使其正常工作。我注释掉了一些数据类型,但我想您会明白的。
这是阅读文档并尝试各种方法的结果。欢迎任何编辑。
Parcel 位于 Android 框架中,因此您的测试只能使用 Expresso 作为 Mikhail 注释,或使用 Robolectric 作为测试运行器。
Robolectric 模拟 Android.jar 并允许进行此类测试,但考虑到您将对 Android 代码进行单元测试...
你必须将跑步者添加到你的测试类中:
@RunWith(AndroidJUnit4::class)
class TestClass {
}