Arun Senthoor Pandian
Arun Senthoor Pandian

Reputation: 381

Mock static method in JUnit 5 using Mockito

I am trying to mock static classes(org.apache.commons.beanutils.Beanutils) for Junit 5 test cases. I came across mockito-inline dependency helps with mocking static classes. I tried to use the mockito-inline in the project for some strange reason it give me compilation error in the absence of mockito-core library.

With mockito-core am getting below:

org.mockito.exceptions.base.MockitoException: 
The used MockMaker PowerMockMaker does not support the creation of static mocks

Mockito's inline mock maker supports static mocks based on the Instrumentation API.
You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'.
Note that Mockito's inline mock maker is not supported on Android.
    at com.xx.xx.xx.AvroCopyPropertiesInvocationTargetExceptionScenario(CreditOfferServiceTest.java:1197)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

Without the core - compilation issue. Please find the test dependency breakdown without mockito-core:

[INFO] +- org.powermock:powermock-api-mockito2:jar:2.0.9:test
[INFO] |  \- org.powermock:powermock-api-support:jar:2.0.9:test
[INFO] |     +- org.powermock:powermock-reflect:jar:2.0.9:test
[INFO] |     \- org.powermock:powermock-core:jar:2.0.9:test
[INFO] +- org.mockito:mockito-inline:jar:3.6.28:test
[INFO] |  \- org.mockito:mockito-core:jar:3.1.0:test
[INFO] |     +- net.bytebuddy:byte-buddy:jar:1.10.10:test
[INFO] |     +- net.bytebuddy:byte-buddy-agent:jar:1.10.10:test
[INFO] |     \- org.objenesis:objenesis:jar:2.6:test
[INFO] +- org.mockito:mockito-junit-jupiter:jar:3.6.0:test
[INFO] |  \- org.junit.jupiter:junit-jupiter-api:jar:5.5.2:test
[INFO] |     +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO] |     \- org.junit.platform:junit-platform-commons:jar:1.5.2

Upvotes: 37

Views: 111638

Answers (6)

Brahim BEN ADDI
Brahim BEN ADDI

Reputation: 53

I have faced this issue while trying to use Mockito5 with JDK8, the thing is that "Instrumentation API" is not supported by JDK8(this is what allows you to mock static classes on runtime) , which is included in JDK9 and later.

Instrumentation API allows you to alter existing byte-code that is loaded in a JVM.

Solution 1 : Here is the work around I did to overcome this issue :

dependencies{
....
    testImplementation group: 'org.mockito', name: 'mockito-inline', version: '4.8.0'

    implementation group: 'net.bytebuddy', name: 'byte-buddy-agent', version: '1.12.14'
}

configurations {
    byteBuddyAgent
    compile.extendsFrom byteBuddyAgent
}

test {

    // Add the Byte Buddy agent to the JVM arguments during testing, which will be retrieved by the inline-mockito during runtime.
    doFirst {
        // Get the list of dependencies.
        List<File> dependencies = configurations.compileClasspath.files.toList()

        // Find the jar file for the `byte-buddy-agent` dependency.
        File byteBuddyAgent = dependencies.find { file -> file.path.contains('byte-buddy-agent') }

        if (byteBuddyAgent != null) {
            // Get the path to the jar file.
             jarPath = byteBuddyAgent.absolutePath
             jvmArgs '-javaagent:' + jarPath
        } else {
            // Handle the case when the desired JAR file is not found.
            println "The 'byte-buddy-agent' jar file was not found in the dependencies."
        }
    }

    finalizedBy jacocoTestReport // report is always generated after tests run
}

Solution 2 : Using PowerMockito wans't practicle for me beacause I need to run jacococ reports to see the code coverage and jacoco doesn't like PowerMockito for some reason.

Upvotes: 1

Sachin Nagode
Sachin Nagode

Reputation: 71

I have some resolutions steps for same.

Please replace you dependency with below .

<dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-inline</artifactId>
                <version>4.5.1</version>
                <scope>test</scope>
            </dependency>

if use 4.5.1 or latest your code will work

Also use your try with resource to mock static method

try (MockedStatic<WelcomeUtil> theMock = Mockito.mockStatic(WelcomeUtil.class)) {
            theMock.when(() -> WelcomeUtil.generateWelcome("John"))
                   .thenReturn("Guten Tag John");

            assertEquals("Guten Tag John", WelcomeUtil.generateWelcome("John"));
        }

Upvotes: 7

Smart Coder
Smart Coder

Reputation: 1748

Add the following per https://www.baeldung.com/mockito-mock-static-methods:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.8.0</version>
    <scope>test</scope>
</dependency>

Upvotes: 13

Sanjay Bharwani
Sanjay Bharwani

Reputation: 4779

In my case we were using spring boot and below dependency for spring-boot-starter-test and mockito-core was coming internally with spring-boot-starter-test

testImplementation 'org.springframework.boot:spring-boot-starter-test'

use gradle dependencies to find this

+--- org.springframework.boot:spring-boot-starter-test -> 2.6.6
|    +--- org.springframework.boot:spring-boot-starter:2.6.6 (*)
|    +--- org.springframework.boot:spring-boot-test:2.6.6
|    |    \--- org.springframework.boot:spring-boot:2.6.6 (*)
|    +--- org.springframework.boot:spring-boot-test-autoconfigure:2.6.6
|    |    +--- org.springframework.boot:spring-boot:2.6.6 (*)
|    |    +--- org.springframework.boot:spring-boot-test:2.6.6 (*)
|    |    \--- org.springframework.boot:spring-boot-autoconfigure:2.6.6 (*)
|    +--- com.jayway.jsonpath:json-path:2.6.0
|    |    +--- net.minidev:json-smart:2.4.7 -> 2.4.8
|    |    |    \--- net.minidev:accessors-smart:2.4.8
|    |    |         \--- org.ow2.asm:asm:9.1 -> 9.3
|    |    \--- org.slf4j:slf4j-api:1.7.30 -> 1.7.36
|    +--- jakarta.xml.bind:jakarta.xml.bind-api:2.3.3
|    |    \--- jakarta.activation:jakarta.activation-api:1.2.2
|    +--- org.assertj:assertj-core:3.21.0
|    +--- org.hamcrest:hamcrest:2.2
|    +--- org.junit.jupiter:junit-jupiter:5.8.2
|    |    +--- org.junit:junit-bom:5.8.2
|    |    |    +--- org.junit.jupiter:junit-jupiter:5.8.2 (c)
|    |    |    +--- org.junit.jupiter:junit-jupiter-api:5.8.2 (c)
|    |    |    +--- org.junit.jupiter:junit-jupiter-params:5.8.2 (c)
|    |    |    \--- org.junit.platform:junit-platform-commons:1.8.2 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-api:5.8.2
|    |    |    +--- org.junit:junit-bom:5.8.2 (*)
|    |    |    +--- org.opentest4j:opentest4j:1.2.0
|    |    |    +--- org.junit.platform:junit-platform-commons:1.8.2
|    |    |    |    +--- org.junit:junit-bom:5.8.2 (*)
|    |    |    |    \--- org.apiguardian:apiguardian-api:1.1.2
|    |    |    \--- org.apiguardian:apiguardian-api:1.1.2
|    |    \--- org.junit.jupiter:junit-jupiter-params:5.8.2
|    |         +--- org.junit:junit-bom:5.8.2 (*)
|    |         +--- org.junit.jupiter:junit-jupiter-api:5.8.2 (*)
|    |         \--- org.apiguardian:apiguardian-api:1.1.2
|    +--- org.mockito:mockito-core:4.0.0
|    |    +--- net.bytebuddy:byte-buddy:1.11.19 -> 1.11.22
|    |    \--- net.bytebuddy:byte-buddy-agent:1.11.19 -> 1.11.22
|    +--- org.mockito:mockito-junit-jupiter:4.0.0
|    |    \--- org.mockito:mockito-core:4.0.0 (*)

So, 2 steps to solve this issue.

Exclude the mockito-core from spring-boot-starter-test

testImplementation ('org.springframework.boot:spring-boot-starter-test') 
 {
   exclude group: 'org.mockito', module :'mockito-core'
 }

And now include the mockito-inline

testImplementation 'org.mockito:mockito-inline:4.6.1'

This will solve the issue.

Upvotes: 19

Amgad Hanafy
Amgad Hanafy

Reputation: 667

You need to use mockito-inline version 3.4.0 or higher and remove mockito-core from your dependencies (mockito-inline depends on mockito-core so it will be retrieved automatically).

That way, you will be using mockito static mocking correctly, but it wouldn't solve the exception that you posted.

To fix it, you need to remove all dependencies of powermock as it conflicts with mockito and causes this error

The used MockMaker PowerMockMaker does not support the creation of static mocks

Upvotes: 27

Eranda
Eranda

Reputation: 1467

You have to add /mockito-extensions/org.mockito.plugins.MockMaker file to the class path containing the value mock-maker-inline. Easiest way to do that is put it in the src/test/resources directory.

For more details check the Mockito documentation.

https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#Mocking_Final

Upvotes: 9

Related Questions