英文:
Mock static java and kotlin
问题
我可以帮你翻译代码的部分。以下是你提供的代码的翻译:
在Java中,我有一个静态类,我想要进行模拟测试,我可以成功地做到这一点。但是当我转换到Kotlin时,测试现在失败,并显示以下错误:
检测到错误的参数匹配器放置或误用:->于TestTest.kt的TestTest.testWrapperStatic$lambda$0中
关于在Kotlin中模拟静态方法是否有什么不同的想法吗?
要模拟的类:
object TextUtilsWrapper {
@JvmStatic
fun createFromParcel(p: Parcel): CharSequence {
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p)
}
}
通过的Java测试用例:
public class TestTest extends BaseMockingUnitTest {
@Test
public void testWrapperStatic() {
Parcel parcel = Mockito.mock(Parcel.class);
final MockedStatic<TextUtilsWrapper> textUtilsWrapperMockedStatic = mockStatic(
TextUtilsWrapper.class);
textUtilsWrapperMockedStatic.when(
() -> TextUtilsWrapper.createFromParcel(any())).thenReturn("hello");
assertThat(TextUtilsWrapper.createFromParcel(parcel), is("hello"));
}
}
失败的Kotlin测试用例:
class TestTest : BaseMockingUnitTest() {
@Test
fun testWrapperStatic() {
val parcel = Mockito.mock(Parcel::class.java)
val textUtilsWrapperMockedStatic = Mockito.mockStatic(
TextUtilsWrapper::class.java
)
textUtilsWrapperMockedStatic.`when`<Any> { createFromParcel(ArgumentMatchers.any()) }
.thenReturn("hello")
MatcherAssert.assertThat(createFromParcel(parcel), Matchers.`is`("hello"))
}
}
请注意,代码中的"<"和"""字符是HTML编码,可能需要根据上下文进行调整。
英文:
I have a static class that I want to mock, I can do this successfully in java. But when I convert to kotlin and tests now fail with the error
Misplaced or misused argument matcher detected here: -> at TestTest.testWrapperStatic$lambda$0(TestTest.kt:19)
Any ideas on what is different when mocking static in kotlin?
Class to mock,
object TextUtilsWrapper {
@JvmStatic
fun createFromParcel(p: Parcel): CharSequence {
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p)
}
}
Passing Java test case,
public class TestTest extends BaseMockingUnitTest {
@Test
public void testWrapperStatic() {
Parcel parcel = Mockito.mock(Parcel.class);
final MockedStatic<TextUtilsWrapper> textUtilsWrapperMockedStatic = mockStatic(
TextUtilsWrapper.class);
textUtilsWrapperMockedStatic.when(
() -> TextUtilsWrapper.createFromParcel(any())).thenReturn("hello");
assertThat(TextUtilsWrapper.createFromParcel(parcel), is("hello"));
}
}
Failing kotlin test case,
class TestTest : BaseMockingUnitTest() {
@Test
fun testWrapperStatic() {
val parcel = Mockito.mock(Parcel::class.java)
val textUtilsWrapperMockedStatic = Mockito.mockStatic(
TextUtilsWrapper::class.java
)
textUtilsWrapperMockedStatic.`when`<Any> { createFromParcel(ArgumentMatchers.any()) }
.thenReturn("hello")
MatcherAssert.assertThat(createFromParcel(parcel), Matchers.`is`("hello"))
}
}
答案1
得分: 2
以下是翻译好的部分:
差异源于Kotlin添加了空值检查代码。
检查您的测试类的反编译源代码:
public final class TextUtilsWrapperTest {
@Test
public final void testWrapperStatic() {
Parcel parcel = (Parcel) Mockito.mock(Parcel.class);
MockedStatic textUtilsWrapperMockedStatic = Mockito.mockStatic(TextUtilsWrapper.class);
textUtilsWrapperMockedStatic.when(TextUtilsWrapperTest::testWrapperStatic$lambda$0)
.thenReturn("hello");
Intrinsics.checkNotNullExpressionValue(parcel, "parcel");
Assertions.assertEquals("hello", TextUtilsWrapper.createFromParcel(parcel));
}
private static final void testWrapperStatic$lambda$0() {
Intrinsics.checkNotNullExpressionValue(ArgumentMatchers.any(), "any()");
TextUtilsWrapper.createFromParcel((Parcel) ArgumentMatchers.any());
}
}
预期事件序列如下:
- 调用参数匹配器并在堆栈上注册
- 拦截模拟的方法调用,并调用
MockMethodAdvice.handleStatic
- 这将调用
ArgumentMatcherStorageImpl.pullLocalizedMatchers
并清除匹配器堆栈。
请参阅:https://stackoverflow.com/questions/22822512/how-do-mockito-matchers-work
不幸的是,Intrinsics.checkNotNullExpressionValue
引发了NullPointerExeption,因为ArgumentMatchers.any()
返回null。
这个NPE被静默忽略,但模拟的方法没有被调用,因此没有调用handleStatic
- 匹配器堆栈未被清除。
在MockedStaticImpl.when
调用时检查匹配器堆栈,并报告InvalidUseOfMatchersException
。
要解决此问题,可以使用mockito-kotlin
提供的参数匹配器:
/** 匹配任何对象,但不包括null。 */
inline fun <reified T : Any> any(): T {
return ArgumentMatchers.any(T::class.java) ?: createInstance()
}
/** 匹配任何内容,包括null。 */
inline fun <reified T : Any> anyOrNull(): T {
return ArgumentMatchers.any<T>() ?: createInstance()
}
希望这些信息对您有所帮助。
英文:
The difference stems from the fact that Kotlin adds null-checking code.
Check the decompiled source of your test class:
public final class TextUtilsWrapperTest {
@Test
public final void testWrapperStatic() {
Parcel parcel = (Parcel)Mockito.mock(Parcel.class);
MockedStatic textUtilsWrapperMockedStatic = Mockito.mockStatic(TextUtilsWrapper.class);
textUtilsWrapperMockedStatic.when(TextUtilsWrapperTest::testWrapperStatic$lambda$0)
.thenReturn("hello");
Intrinsics.checkNotNullExpressionValue(parcel, "parcel");
Assertions.assertEquals("hello", TextUtilsWrapper.createFromParcel(parcel));
}
private static final void testWrapperStatic$lambda$0() {
Intrinsics.checkNotNullExpressionValue(ArgumentMatchers.any(), "any()");
TextUtilsWrapper.createFromParcel((Parcel)ArgumentMatchers.any());
}
}
The expected event sequence is:
- argument matcher is called and registered on stack
- mocked method call is intercepted and
MockMethodAdvice.handleStatic
is called - this calls
ArgumentMatcherStorageImpl.pullLocalizedMatchers
and clears the matchers stack.
See: https://stackoverflow.com/questions/22822512/how-do-mockito-matchers-work
Unfortunately, Intrinsics.checkNotNullExpressionValue
throws a NullPointerExeption, as ArgumentMatchers.any()
returnes null.
This NPE is silently ignored, but mocked method is not called, and thus handleStatic is not called - the matchers stack is not cleared.
The matchers stack is checked upon MockedStaticImpl.when
call, and the InvalidUseOfMatchersException
is reported.
To solve, use mockito-kotlin
provided argument matchers:
/** Matches any object, excluding nulls. */
inline fun <reified T : Any> any(): T {
return ArgumentMatchers.any(T::class.java) ?: createInstance()
}
/** Matches anything, including nulls. */
inline fun <reified T : Any> anyOrNull(): T {
return ArgumentMatchers.any<T>() ?: createInstance()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论