bug: mockito-android crashes instead of warning when running unit tests
See original GitHub issueBug report
We are seeing a strange crash coming from AndroidByteBuddyMockMaker
when calling Mockito.mock
in unit tests. It appears that it’s crashing because it is trying to use the PluginRegistry
logger during initialization of the registry: PluginRegistry
field on Plugins
.
It’s pretty clear looking at the code in AndroidByteBuddyMockMaker
that the intended behavior is for a warning to be issued, but instead it crashes with a somewhat garbled error (pasted below).
This only happens when you include mockito-android
in the classpath when running unit tests. This is normally a problem solvable by the user, except there appears to be a bug in Android Studio 3.4.0 where switching back and forth between build variants adds androidTestImplementation
dependencies to the classpath even for unit tests 🤷♂.
(We plan to open a separate bug report with Android Studio to cover that)
Versions
mockito: 2.27.0 android studio: 3.4.0 jre: 1.8.0_152 x86
Steps to Repro
- create a new gradle project with
testImplementation("org.mockito:mockito-android:2.27.0")
independencies
- create a unit test with the following code:
package com.example.mockitoandroidcrash
import org.junit.Test
import org.junit.Assert.*
import org.mockito.Mockito.mock
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
open class Example
@Test
fun `uses default SubclassByteBuddyMockMaker for mocking`() {
val exampleMock = mock(Example::class.java)
assertTrue(exampleMock is Example)
}
}
- Run the test for ExampleUnitTest
Expected Behavior
- the test should should run and pass, but log a warning message:
IMPORTANT NOTE FROM MOCKITO:
You included the 'mockito-android' dependency in a non-Android environment.
The Android mock maker was disabled. You should only include the latter in your 'androidTestCompile' configuration
If disabling was a mistake, you can set the 'org.mockito.mock.android' property to 'true' to override this detection.
Visit https://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.1 for more information
Actual Behavior
- It fails the test, crashing with the following error message and stack trace:
java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMaker (alternate: null)
at org.mockito.internal.configuration.plugins.PluginLoader$1.invoke(PluginLoader.java:74)
at com.sun.proxy.$Proxy7.isTypeMockable(Unknown Source)
at org.mockito.internal.util.MockUtil.typeMockabilityOf(MockUtil.java:29)
at org.mockito.internal.util.MockCreationValidator.validateType(MockCreationValidator.java:22)
at org.mockito.internal.creation.MockSettingsImpl.validatedSettings(MockSettingsImpl.java:240)
at org.mockito.internal.creation.MockSettingsImpl.build(MockSettingsImpl.java:228)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:61)
at org.mockito.Mockito.mock(Mockito.java:1907)
at org.mockito.Mockito.mock(Mockito.java:1816)
at com.example.mockitoandroidcrash.ExampleUnitTest.uses default SubclassByteBuddyMockMaker for mocking(ExampleUnitTest.kt:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.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.InvokeMethod.evaluate(InvokeMethod.java:17)
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$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.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$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.IllegalStateException: Failed to load interface org.mockito.plugins.MockMaker implementation declared in sun.misc.CompoundEnumeration@57fa26b7
at org.mockito.internal.configuration.plugins.PluginInitializer.loadImpl(PluginInitializer.java:54)
at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:57)
at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:44)
at org.mockito.internal.configuration.plugins.PluginRegistry.<init>(PluginRegistry.java:22)
at org.mockito.internal.configuration.plugins.Plugins.<clinit>(Plugins.java:19)
at org.mockito.internal.util.MockUtil.<clinit>(MockUtil.java:24)
... 37 more
Caused by: java.lang.NullPointerException
at org.mockito.internal.configuration.plugins.Plugins.getMockitoLogger(Plugins.java:66)
at org.mockito.android.internal.creation.AndroidByteBuddyMockMaker.<init>(AndroidByteBuddyMockMaker.java:24)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at org.mockito.internal.configuration.plugins.PluginInitializer.loadImpl(PluginInitializer.java:49)
... 42 more
Issue Analytics
- State:
- Created 4 years ago
- Reactions:10
- Comments:9 (4 by maintainers)
Top GitHub Comments
This is working as intended. You need to add
mockito-android
in theandroidTestImplementation
scope per our documentation: https://static.javadoc.io/org.mockito/mockito-core/2.27.0/org/mockito/Mockito.html#0.1My reading of the code in
AndroidByteBuddyMockMaker
seems to be that if you do load mockito-android in a unit test, it should log a warning and delegate to the default MockMaker implementation, not raise an exception.A separate issue, which is what led to me discovering this in the first place, is that Android Studio 3.4.0 doesn’t seem to be doing the right thing when running tests in the IDE: it’s sometimes loading androidTestImplementation dependencies during unit test runs.
Assuming you’ve changed
testImplementation
toandroidTestImplementation
, you can still reproduce this crash: open the project in Android Studio 3.4.0 (currently the latest stable build), click on “Build Variants” on the left bar, and switch the variant to “release”, then run theExampleUnitTest
test. It is failing for me with the error in the issue description.Hopefully this helps.