Powermock: PowerMock with Kotlin methods using backticks naming fails

Created on 26 Apr 2018  路  5Comments  路  Source: powermock/powermock

I was trying to make methods naming more readable and decided to use _backticks_ to achieve it but unfortunately PowerMock's Javasist doesn't play well here (bytecode manipulations break everything I guess)... I just can't run tests (even via gradle task), so it's not a problem of Android Studio.

Minimal code to reproduce the issue::

@RunWith(PowerMockRunner::class)
class ActionsSenderTest {
    @Test
    fun `when do something and we have something under the hood then somethings should be something testXXX`() {
        // given something
        val something: Any = powerMock()

        // when do something (or just nothing)
        doAnswer { invocationOnMock ->
            val completeListener: Runnable = invocationOnMock [2]
            completeListener.run()
            null
        }.whenever(something).equals(nonNull())

        // then check something
        assertThat(2).isPositive()
    }
}

inline fun <reified T> powerMock() = PowerMockito.mock(T::class.java)!!
fun <T> Stubber.whenever(mock: T) = `when`(mock)!!
inline operator fun <reified T> InvocationOnMock.get(index: Int) = getArgument<T>(index)
inline fun <reified T> nonNull() = Mockito.any(T::class.java)

Issue:

java.lang.IllegalStateException: Failed to transform class with name com.test.actions.ActionsSenderTest. Reason: [source error] ) is missing
    at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:284)
    at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:192)
    at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass1(DeferSupportingClassLoader.java:77)
    at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:161)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:48)
    at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:108)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.<init>(JUnit4TestSuiteChunkerImpl.java:71)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.<init>(AbstractCommonPowerMockRunner.java:32)
    at org.powermock.modules.junit4.PowerMockRunner.<init>(PowerMockRunner.java:34)
    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 org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
    at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)
    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)
    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.AppMainV2.main(AppMainV2.java:131)
Caused by: javassist.CannotCompileException: [source error] ) is missing
    at javassist.expr.FieldAccess.replace(FieldAccess.java:218)
    at org.powermock.core.transformers.impl.AbstractMainMockTransformer$PowerMockExpressionEditor.edit(AbstractMainMockTransformer.java:339)
    at javassist.expr.ExprEditor.loopBody(ExprEditor.java:198)
    at javassist.expr.ExprEditor.doit(ExprEditor.java:91)
    at javassist.CtClassType.instrument(CtClassType.java:1465)
    at org.powermock.core.transformers.impl.ClassMockTransformer.transformMockClass(ClassMockTransformer.java:65)
    at org.powermock.core.transformers.impl.AbstractMainMockTransformer.transform(AbstractMainMockTransformer.java:62)
    at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:265)
    ... 31 more
Caused by: compile error: ) is missing
    at javassist.compiler.Parser.parsePrimaryExpr(Parser.java:1250)
    at javassist.compiler.Parser.parsePostfix(Parser.java:1031)
    at javassist.compiler.Parser.parseCast(Parser.java:921)
    at javassist.compiler.Parser.parseUnaryExpr(Parser.java:886)
    at javassist.compiler.Parser.parseBinaryExpr(Parser.java:775)
    at javassist.compiler.Parser.parseConditionalExpr(Parser.java:719)
    at javassist.compiler.Parser.parseExpression(Parser.java:699)
    at javassist.compiler.Parser.parseExpression(Parser.java:704)
    at javassist.compiler.Parser.parseDeclarationOrExpression(Parser.java:591)
    at javassist.compiler.Parser.parseStatement(Parser.java:277)
    at javassist.compiler.Parser.parseBlock(Parser.java:289)
    at javassist.compiler.Parser.parseStatement(Parser.java:243)
    at javassist.compiler.Parser.parseIf(Parser.java:311)
    at javassist.compiler.Parser.parseStatement(Parser.java:255)
    at javassist.compiler.Parser.parseBlock(Parser.java:289)
    at javassist.compiler.Parser.parseStatement(Parser.java:243)
    at javassist.compiler.Javac.compileStmnt(Javac.java:565)
    at javassist.expr.FieldAccess.replace(FieldAccess.java:212)
    ... 38 more

What steps will reproduce the problem?
Run Unit tests' task via gradle or via Android Studio.

What is the expected output?
All tests are passed.

What do you see instead?
Exception.

What version of the product are you using?

  • testsJunitVersion = '4.12'
  • testsMockitoVersion = '2.4.0'
  • testsPowerMockitoVersion = '1.7.0RC4'
  • testsAssertJVersion = '3.6.2'
  • testJUnitParamsVersion = '1.1.0'
  • kotlinVersion = '1.2.40'
classpath "com.android.tools.build:gradle:3.0.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"

apply plugin: 'kotlin-android'

dependencies {
    // kotlin
    testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}"
    testImplementation "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}"
    testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion}"
    // convenient tests libs
    testImplementation "junit:junit:${testsJunitVersion}"
    testImplementation "org.mockito:mockito-core:${testsMockitoVersion}"
    testImplementation "org.powermock:powermock-module-junit4:${testsPowerMockitoVersion}"
    testImplementation "org.powermock:powermock-api-mockito2:${testsPowerMockitoVersion}"
    testImplementation "org.assertj:assertj-core:${testsAssertJVersion}"
    testImplementation "pl.pragmatists:JUnitParams:${testJUnitParamsVersion}"
}

project.afterEvaluate {
    // skip Kotlin for production
    android.sourceSets.all { sourceSet ->
        if (!sourceSet.name.startsWith('test') || !sourceSet.name.startsWith('androidTest')) {
            sourceSet.kotlin.setSrcDirs([])
        }
    }
}

Most helpful comment

I also had the same issue and I found the solution for this issue: You should use `` from the name of Class Test, only should use _ in the name. Ex: abc_def

All 5 comments

Just encountered this same issue 馃憤

I was using a combination powermock and mockito-kotlin and experienced the same issue, but only when using mocking via:

val mock = mock<MyClass> {
    on { getText() } doReturn "text"
  }

it worked when typing like this:

mock:MyClass = mock()
whenever(mock.getText()).thenReturn("text")

The static mock was in another test. The test is using backticked method name. No clue why it works when using the other mocking syntax.

I also had the same issue and I found the solution for this issue: You should use `` from the name of Class Test, only should use _ in the name. Ex: abc_def

In the end, I use MockK. It supports Kotlin completely. You should try this.

@anggrayudi mockk can't mock constructors with custom arguments 8(
so i use both

face same issue here, and it was unexpected

Was this page helpful?
0 / 5 - 0 ratings