如何模拟 Parcel.recycle()?
How to mock Parcel.recycle()?
在我们的 Android 应用程序中,我们管理医疗案例,该应用程序部分使用 Kotlin 编写。用户可以编辑它们。我们通过在演示者中创建一个克隆来验证更改,仅更改副本并将其与原始文件进行比较。我使用 Parcelable 克隆案例对象如下:
public Case cloneObject() {
Parcel parcel = null;
try {
parcel = Parcel.obtain();
parcel.writeParcelable(this, 0);
parcel.setDataPosition(0);
return parcel.readParcelable(Case.class.getClassLoader());
} finally {
if (parcel != null) {
parcel.recycle();
}
}
}
在应用程序中,我们会像这样验证对案例的更改:
override fun validateHasChanges(): Boolean {
return !(model.updatedCase.title == model.originalCase.title &&
model.updatedCase.description == model.originalCase.description &&
model.updatedCase.category == model.originalCase.category &&
model.updatedCase.visibility == model.originalCase.visibility &&
areCaseFilesEqual() &&
model.updatedCase.recommendedFor == model.originalCase.recommendedFor &&
!model.wasConsentClicked &&
!model.wasImagesClicked)
}
现在我想写一个单元测试来验证上面的正确性。问题是 Parcel 有静态方法和最终方法,还有一个最终无效方法 recycle()。我使用 PowerMockito 克服了其中的大部分问题,但在花了好几天时间后,我无论如何都无法模拟回收。这是目前的样子。
@RunWith(PowerMockRunner::class)
@PrepareForTest(Case::class, Parcel::class)
class QuickPostTest : BehaviorSpec() {
@Test
fun `validate has changes when category is different`() {
PowerMockito.mockStatic(Parcel::class.java)
val spy = PowerMockito.spy(Case())
val spy2 = PowerMockito.mock(Parcel::class.java)
PowerMockito.doNothing().`when`(spy2.recycle())
//suppress(method(Parcel::class.java, "recycle"))
Mockito.`when`(Parcel.obtain()).thenReturn(Whitebox.newInstance(Parcel::class.java))
Mockito.`when`(spy.cloneObject()).thenReturn(cloneObject(spy))
val originalCase = Case()
originalCase.title = "Cool"
val specialty = Specialty()
specialty.id = "anaesthetics"
val specialty2 = Specialty()
specialty2.id = "anaesthetics.anaesthesia.cardiothoracic"
originalCase.addSpecialty(specialty)
val model = BaseCreateCaseModel(originalCase, true)
model.updatedCase.addSpecialty(specialty2)
val presenter = CreateCaseQuickPresenter(originalCase)
presenter.setModel(model)
assertTrue(presenter.validateHasChanges())
}
private fun cloneObject(aCase: Case): Case {
var parcel: Parcel? = null
try {
parcel = Parcel.obtain()
parcel!!.writeParcelable(aCase, 0)
parcel.setDataPosition(0)
return parcel.readParcelable(Case::class.java.classLoader)
} finally {
if (parcel != null) {
parcel.recycle()
}
}
}
}
我应该如何修改它才能使其工作?
这不是我问题的直接答案,但我相信它是正确的。我选择 Parcel 进行克隆是因为我确信它是最简单的解决方案,因为 Java 中的 Cloneable 接口已损坏并且复制构造函数太复杂了。但是我错了。将 Parcelable 添加到我的模型中,并在我的 Presenter 中添加 Android 依赖项。事实证明,这种情况下的复制构造函数并没有那么复杂,即使我的 class 层次结构非常深。所以我这样做了,删除了间谍,现在可以使用了。我不得不保留 PowerMockito,因为我需要 Parcelable 来传递 Case 对象,但我在 Presenter 中不需要它,所以 mockStatic 就足够了。
测试结果如下:
@RunWith(PowerMockRunner::class)
@PrepareForTest(Case::class, Parcel::class)
class QuickPostTest : BehaviorSpec() {
@Test
fun `validate has changes when category is different`() {
PowerMockito.mockStatic(Parcel::class.java)
val originalCase = Case()
originalCase.title = "Cool"
val specialty = Specialty()
specialty.id = "anaesthetics"
specialty.isActive = true
val specialty2 = Specialty()
specialty2.id = "anaesthetics.anaesthesia.cardiothoracic"
specialty2.isActive = true
originalCase.addSpecialty(specialty)
val model = BaseCreateCaseModel(originalCase, true)
model.updatedCase.addSpecialty(specialty2)
val presenter = CreateCaseQuickPresenter(originalCase)
presenter.setModel(model)
assertTrue(presenter.validateHasChanges())
}
}
在我们的 Android 应用程序中,我们管理医疗案例,该应用程序部分使用 Kotlin 编写。用户可以编辑它们。我们通过在演示者中创建一个克隆来验证更改,仅更改副本并将其与原始文件进行比较。我使用 Parcelable 克隆案例对象如下:
public Case cloneObject() {
Parcel parcel = null;
try {
parcel = Parcel.obtain();
parcel.writeParcelable(this, 0);
parcel.setDataPosition(0);
return parcel.readParcelable(Case.class.getClassLoader());
} finally {
if (parcel != null) {
parcel.recycle();
}
}
}
在应用程序中,我们会像这样验证对案例的更改:
override fun validateHasChanges(): Boolean {
return !(model.updatedCase.title == model.originalCase.title &&
model.updatedCase.description == model.originalCase.description &&
model.updatedCase.category == model.originalCase.category &&
model.updatedCase.visibility == model.originalCase.visibility &&
areCaseFilesEqual() &&
model.updatedCase.recommendedFor == model.originalCase.recommendedFor &&
!model.wasConsentClicked &&
!model.wasImagesClicked)
}
现在我想写一个单元测试来验证上面的正确性。问题是 Parcel 有静态方法和最终方法,还有一个最终无效方法 recycle()。我使用 PowerMockito 克服了其中的大部分问题,但在花了好几天时间后,我无论如何都无法模拟回收。这是目前的样子。
@RunWith(PowerMockRunner::class)
@PrepareForTest(Case::class, Parcel::class)
class QuickPostTest : BehaviorSpec() {
@Test
fun `validate has changes when category is different`() {
PowerMockito.mockStatic(Parcel::class.java)
val spy = PowerMockito.spy(Case())
val spy2 = PowerMockito.mock(Parcel::class.java)
PowerMockito.doNothing().`when`(spy2.recycle())
//suppress(method(Parcel::class.java, "recycle"))
Mockito.`when`(Parcel.obtain()).thenReturn(Whitebox.newInstance(Parcel::class.java))
Mockito.`when`(spy.cloneObject()).thenReturn(cloneObject(spy))
val originalCase = Case()
originalCase.title = "Cool"
val specialty = Specialty()
specialty.id = "anaesthetics"
val specialty2 = Specialty()
specialty2.id = "anaesthetics.anaesthesia.cardiothoracic"
originalCase.addSpecialty(specialty)
val model = BaseCreateCaseModel(originalCase, true)
model.updatedCase.addSpecialty(specialty2)
val presenter = CreateCaseQuickPresenter(originalCase)
presenter.setModel(model)
assertTrue(presenter.validateHasChanges())
}
private fun cloneObject(aCase: Case): Case {
var parcel: Parcel? = null
try {
parcel = Parcel.obtain()
parcel!!.writeParcelable(aCase, 0)
parcel.setDataPosition(0)
return parcel.readParcelable(Case::class.java.classLoader)
} finally {
if (parcel != null) {
parcel.recycle()
}
}
}
}
我应该如何修改它才能使其工作?
这不是我问题的直接答案,但我相信它是正确的。我选择 Parcel 进行克隆是因为我确信它是最简单的解决方案,因为 Java 中的 Cloneable 接口已损坏并且复制构造函数太复杂了。但是我错了。将 Parcelable 添加到我的模型中,并在我的 Presenter 中添加 Android 依赖项。事实证明,这种情况下的复制构造函数并没有那么复杂,即使我的 class 层次结构非常深。所以我这样做了,删除了间谍,现在可以使用了。我不得不保留 PowerMockito,因为我需要 Parcelable 来传递 Case 对象,但我在 Presenter 中不需要它,所以 mockStatic 就足够了。
测试结果如下:
@RunWith(PowerMockRunner::class)
@PrepareForTest(Case::class, Parcel::class)
class QuickPostTest : BehaviorSpec() {
@Test
fun `validate has changes when category is different`() {
PowerMockito.mockStatic(Parcel::class.java)
val originalCase = Case()
originalCase.title = "Cool"
val specialty = Specialty()
specialty.id = "anaesthetics"
specialty.isActive = true
val specialty2 = Specialty()
specialty2.id = "anaesthetics.anaesthesia.cardiothoracic"
specialty2.isActive = true
originalCase.addSpecialty(specialty)
val model = BaseCreateCaseModel(originalCase, true)
model.updatedCase.addSpecialty(specialty2)
val presenter = CreateCaseQuickPresenter(originalCase)
presenter.setModel(model)
assertTrue(presenter.validateHasChanges())
}
}