question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Attempt to mock a Kotlin-sealed class contained in another class fails when using mock-maker-inline

See original GitHub issue

This issue is raised when attempting to mock a sealed class that is contained in another class. Sealed classes are used in Kotlin to restrict class hierarchies.

class MyTest {

    abstract class AbstractClass class private constructor()

    sealed class SealedClass

    @Test
    fun mockAbstract() {
        Mockito.mock(AbstractClass::class.java) // Succeeds
    }

    @Test
    fun mockSealedClass() {
        Mockito.mock(SealedClass::class.java) // Fails
    }
}

Now the generated byte code for both classes is similar, except for the access flags:

// ================MyTest$AbstractClass.class =================
// class version 50.0 (50)
// access flags 0x421
public abstract class MyTest$AbstractClass {


  // access flags 0x2
  private <init>()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this LMyTest$AbstractClass; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  @Lkotlin/Metadata;(mv={1, 1, 2}, bv={1, 0, 1}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\u0008&\u0018\u00002\u00020\u0001B\u0007\u0008\u0002\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0003"}, d2={"LMyTest$AbstractClass;", "", "()V", "test sources for module ui"})
- // access flags 0x409
- public static abstract INNERCLASS MyTest$AbstractClass MyTest AbstractClass
  // compiled from: Test.kt
}
// ================MyTest$SealedClass.class =================
// class version 50.0 (50)
// access flags 0x421
public abstract class MyTest$SealedClass {


  // access flags 0x2
  private <init>()V
   L0
    LINENUMBER 5 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this LMyTest$SealedClass; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  @Lkotlin/Metadata;(mv={1, 1, 2}, bv={1, 0, 1}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\u00086\u0018\u00002\u00020\u0001B\u0007\u0008\u0002\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0003"}, d2={"LMyTest$SealedClass;", "", "()V", "test sources for module ui"})
+ // access flags 0x9
+ public static INNERCLASS MyTest$SealedClass MyTest SealedClass
  // compiled from: Test.kt
}

When turning off mock-maker-inline, both cases succeed. It also does not occur when the sealed class is not nested.

The stacktrace:

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class MyTest$SealedClass.

If you're not sure why you're getting this error, please report to the mailing list.


Java               : 1.8
JVM vendor name    : Oracle Corporation
JVM vendor version : 25.76-b03
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 1.8.0_76-release-b03
JVM info           : mixed mode
OS name            : Linux
OS version         : 4.4.0-45-generic


You are seeing this disclaimer because Mockito is configured to create inlined mocks.
You can learn about inline mocks and their limitations under item #39 of the Mockito class javadoc.

Underlying exception : java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the class modifiers

	at MyTest.mockSealedClass(Test.kt:17)
	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.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
	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 com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the class modifiers
	at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
	at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.triggerRetransformation(InlineBytecodeGenerator.java:98)
	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.mockClass(InlineBytecodeGenerator.java:78)
	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$CachedBytecodeGenerator.getOrGenerateMockClass(TypeCachingBytecodeGenerator.java:87)
	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:34)
	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMockType(InlineByteBuddyMockMaker.java:164)
	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMock(InlineByteBuddyMockMaker.java:145)
	at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
	at org.mockito.internal.MockitoCore.mock(MockitoCore.java:63)
	at org.mockito.Mockito.mock(Mockito.java:1632)
	at org.mockito.Mockito.mock(Mockito.java:1545)
	... 28 more

Using Mockito version 2.2.9.

  • The mockito message in the stacktrace have useful information, but it didn’t help
  • The problematic code (if that’s possible) is copied here; Note that some configuration are impossible to mock via Mockito
  • Provide versions (mockito / jdk / os / any other relevant information)
  • Provide a Short, Self Contained, Correct (Compilable), Example of the issue (same as any question on stackoverflow.com)
  • Read the contributing guide

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
raphwcommented, Nov 11, 2016

I filed an issue at Kotlin: https://youtrack.jetbrains.com/issue/KT-14774

There is not much we can do as the Java reflection API does not correctly expose that the Bar class is abstract which is information we rely on. As said, Kotlin corrupts the class file’s inner class modifier which is ignored by the JVM’s runtime but applied by the reflection API. This puts our mocking engine off track.

0reactions
nhaarmancommented, Dec 27, 2016

Kotlin 1.0.6 has been released with a fix for this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to mock final classes on Kotlin using Mockito 2 (KAD 23)
This means that if you want to mock a class (something that may be quite common in Java testing), you need to either...
Read more >
Cannot mock final Kotlin class using Mockito 2 - Stack Overflow
The test fails when we try to initialise the mocks in the setUp() method. Please note I am using Mockito version 2 and...
Read more >
Mockito cannot mock because : final class in Kotlin - MindOrks
In this blog, we will talk about how we can mock the final class using Mockito. By default, we can't mock the final...
Read more >
[Solved]-Cannot mock final Kotlin class using Mockito 2-kotlin
PowerMock implements its own MockMaker which leads to incompatibility with Mockito mock-maker-inline, even if PowerMock is just added as a dependency and not ......
Read more >
Kotlin Sealed Class - DigitalOcean
In Kotlin, Sealed Classes can be termed as Enum classes on steroids. Sealed classes allow us to create instances with different types, unlike ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found