我怎样才能让 Mockito 在 androidTest 中工作
How can I get Mockito working in androidTest
在我的测试中,如何模拟我写的 class?
这是我的测试代码:
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@RunWith(AndroidJUnit4.class)
public class SampleTest {
@Mock
Sample mySample;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldMockSample() {
verify(mySample, never()).neverCallMe();
}
}
样本只是一个假人 class。
public class Sample {
public void neverCallMe() {}
}
如何摆脱这个错误?
java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils at
org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167)
at
org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at
org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
at
org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117) at
org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109) at
org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105) at
org.mockito.cglib.proxy.Enhancer.(Enhancer.java:70) at
org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95)
at
org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57)
at
org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
at
org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33) at
org.mockito.internal.MockitoCore.mock(MockitoCore.java:59) at
org.mockito.Mockito.spy(Mockito.java:1368)
at java.lang.reflect.Method.invokeNative(Native Method) at
java.lang.reflect.Method.invoke(Method.java:515) at
org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at
org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at
org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at
org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at
org.junit.runners.ParentRunner.run(ParentRunner.java:363) at
org.junit.runners.Suite.runChild(Suite.java:128) at
org.junit.runners.Suite.runChild(Suite.java:27) at
org.junit.runners.ParentRunner.run(ParentRunner.java:290) at
org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at
org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at
org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at
org.junit.runners.ParentRunner.run(ParentRunner.java:363) at
org.junit.runner.JUnitCore.run(JUnitCore.java:137) at
org.junit.runner.JUnitCore.run(JUnitCore.java:115) at
android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at
android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:228)
at
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1741)
java.lang.NoClassDefFoundError:
org/mockito/internal/creation/cglib/ClassImposterizer at
org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95)
at
org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57)
at
org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
at
org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33) at
org.mockito.internal.MockitoCore.mock(MockitoCore.java:59) at
org.mockito.Mockito.spy(Mockito.java:1368)
at java.lang.reflect.Method.invokeNative(Native Method) at
java.lang.reflect.Method.invoke(Method.java:515) at
org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at
org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at
org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at
org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at
org.junit.runners.ParentRunner.run(ParentRunner.java:363) at
org.junit.runners.Suite.runChild(Suite.java:128) at
org.junit.runners.Suite.runChild(Suite.java:27) at
org.junit.runners.ParentRunner.run(ParentRunner.java:290) at
org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at
org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at
org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at
org.junit.runners.ParentRunner.run(ParentRunner.java:363) at
org.junit.runner.JUnitCore.run(JUnitCore.java:137) at
org.junit.runner.JUnitCore.run(JUnitCore.java:115) at
android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at
android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:228)
at
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1741)
我在 gradle 文件中使用了以下依赖项:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.1'
androidTestCompile 'com.android.support:support-annotations:22.2.1'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'org.objenesis:objenesis:2.1'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'org.hamcrest:hamcrest-library:1.3'
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
}
默认情况下,Mockito 使用 CGLib 或 ByteBuddy,它们都会生成 .class
个文件。您 运行 在 Android 设备或模拟器上,因此 .class
文件无济于事;您需要 .dex
格式。
调整您的依赖项以使用 DexMaker,这将覆盖 Mockito 的默认设置并允许在 Android 环境中进行模拟。
自版本 2.6.+ 起,Mockito 添加了一个适用于 Android 的新工件,无需任何其他依赖项(即不再需要导入 DexMaker)。 (Reference)
只需使用 org.mockito:mockito-android
作为检测单元测试 (androidTest
) 的依赖项。您仍然会使用通常的 org.mockito:mockito-core
进行本地单元测试。
示例:
dependencies {
...
testImplemenation 'org.mockito:mockito-core:2.7.15'
androidTestImplementation 'org.mockito:mockito-android:2.7.15'
...
}
添加这些依赖项
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1")
testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test:core:1.4.0")
testImplementation("org.mockito:mockito-android:4.2.0")
testImplementation("org.mockito:mockito-inline:4.2.0")
testImplementation("org.mockito:mockito-core:4.2.0")
你可以像这样使用 mockito:
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
@get:Rule
val composeTestRule = createComposeRule()
private lateinit var viewModel: HomeScreenViewModel
@Mock
private val sampleUseCase = mock(SampleUseCase::class.java)
@Before
fun setup() {
runBlockingTest {
`when`(sampleUseCase.invoke(anyInt(), anyString())).thenReturn(
NetworkDataState.Success(listOf(
SampleObject(id = 1),
SampleObject(id = 2),
SampleObject(id = 3),
))
)
viewModel = HomeScreenViewModel(
sampleUseCase
)
}
}
@Test
fun navigationTest() {
composeTestRule.setContent {
AppTheme {
MainScreen(
navController = rememberNavController(),
viewModel = viewModel
)
}
}
composeTestRule
.onNodeWithContentDescription("chips")
.performScrollToIndex(4)
}
}
在我的测试中,如何模拟我写的 class?
这是我的测试代码:
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@RunWith(AndroidJUnit4.class)
public class SampleTest {
@Mock
Sample mySample;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldMockSample() {
verify(mySample, never()).neverCallMe();
}
}
样本只是一个假人 class。
public class Sample {
public void neverCallMe() {}
}
如何摆脱这个错误?
java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167) at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217) at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145) at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117) at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109) at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105) at org.mockito.cglib.proxy.Enhancer.(Enhancer.java:70) at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49) at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59) at org.mockito.Mockito.spy(Mockito.java:1368)
at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54) at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:228) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1741)
java.lang.NoClassDefFoundError: org/mockito/internal/creation/cglib/ClassImposterizer at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49) at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59) at org.mockito.Mockito.spy(Mockito.java:1368)
at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54) at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:228) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1741)
我在 gradle 文件中使用了以下依赖项:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.1'
androidTestCompile 'com.android.support:support-annotations:22.2.1'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'org.objenesis:objenesis:2.1'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'org.hamcrest:hamcrest-library:1.3'
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
}
默认情况下,Mockito 使用 CGLib 或 ByteBuddy,它们都会生成 .class
个文件。您 运行 在 Android 设备或模拟器上,因此 .class
文件无济于事;您需要 .dex
格式。
调整您的依赖项以使用 DexMaker,这将覆盖 Mockito 的默认设置并允许在 Android 环境中进行模拟。
自版本 2.6.+ 起,Mockito 添加了一个适用于 Android 的新工件,无需任何其他依赖项(即不再需要导入 DexMaker)。 (Reference)
只需使用 org.mockito:mockito-android
作为检测单元测试 (androidTest
) 的依赖项。您仍然会使用通常的 org.mockito:mockito-core
进行本地单元测试。
示例:
dependencies {
...
testImplemenation 'org.mockito:mockito-core:2.7.15'
androidTestImplementation 'org.mockito:mockito-android:2.7.15'
...
}
添加这些依赖项
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1")
testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test:core:1.4.0")
testImplementation("org.mockito:mockito-android:4.2.0")
testImplementation("org.mockito:mockito-inline:4.2.0")
testImplementation("org.mockito:mockito-core:4.2.0")
你可以像这样使用 mockito:
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
@get:Rule
val composeTestRule = createComposeRule()
private lateinit var viewModel: HomeScreenViewModel
@Mock
private val sampleUseCase = mock(SampleUseCase::class.java)
@Before
fun setup() {
runBlockingTest {
`when`(sampleUseCase.invoke(anyInt(), anyString())).thenReturn(
NetworkDataState.Success(listOf(
SampleObject(id = 1),
SampleObject(id = 2),
SampleObject(id = 3),
))
)
viewModel = HomeScreenViewModel(
sampleUseCase
)
}
}
@Test
fun navigationTest() {
composeTestRule.setContent {
AppTheme {
MainScreen(
navController = rememberNavController(),
viewModel = viewModel
)
}
}
composeTestRule
.onNodeWithContentDescription("chips")
.performScrollToIndex(4)
}
}