38

I'm removing Powermock from the project I'm currently working on, so I'm trying to rewrite some existing unitary test only with Mockito (mockito-core-2.2.28).

When I run the test, I have the following error:

org.mockito.exceptions.base.MockitoException:

Cannot mock/spy class com.ExternalpackagePath.Externalclass

Mockito cannot mock/spy because :

  • final class

I know that this question has already been asked (How to mock a final class with mockito, Mock objects calling final classes static methods with Mockito), but I didn't find the answer I'm looking for.

Here is an extract of my code :

public class MyClassToTest extends TestCase {
    private MyClass myClass;
    @Mock private Externalclass ext;  // This class is final, I would like to mock it

    @Override
    protected void setUp() throws Exception {
        MockitoAnnotations.initMocks(this); // <<<< The exception is thrown here
        ext = Mockito.mock(Externalclass.class);
    }
}

As mentioned in the Mockito documentation (https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2, §Mock the unmockable), I added the org.mockito.plugins.MockMaker file. This is the tree of my project :

  • project
    • src
      • com.packagePath.myPackage
        • myClass
    • test
      • com.packagePath.myPackage
        • myClassToTest
      • resources
        • mockito-extensions
          • org.mockito.plugins.MockMaker

I also tries to put the "resources" directory in "src", in a subdir called "test", but the result is still the same.

I thought that mocking a final was possible with Mockito v2. Does someone have an idea of what is missing here ?

Thanks!

Community
  • 1
  • 1
Ptiseb
  • 795
  • 1
  • 7
  • 19
  • 2
    The file must be named org.mockito.plugins.MockMaker, not org.mockito.plugins. – JB Nizet Dec 05 '16 at 17:05
  • Woops, sorry, I forgot the end of the line when I made the copy/past, the name of file is well written in my case. My bad! I edited the text description – Ptiseb Dec 05 '16 at 17:10
  • 2
    I was facing the same issue for hours. I use intellij for development. I went to project structure and after creating the resource directory I just marked it as resource and it started working. – Aditya Sharma Apr 22 '20 at 17:21
  • 1
    Now I use testImplementation "org.mockito:mockito-inline:$mockito_version" – CanonicalBear Mar 19 '21 at 08:49

9 Answers9

69

Weird that your solution seems to work.
According to their documentation on Github it says.

Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:

mock-maker-inline

After you created this file, Mockito will automatically use this new engine and one can do :

 final class FinalClass {
   final String finalMethod() { return "something"; }
 }

 FinalClass concrete = new FinalClass(); 

 FinalClass mock = mock(FinalClass.class);
 given(mock.finalMethod()).willReturn("not anymore");

 assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());

In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios. Stay tuned and please let us know what you think of this feature!

My working structure now looks like this.

enter image description here

Community
  • 1
  • 1
timr
  • 6,668
  • 7
  • 47
  • 79
  • 7
    I very much appreciate that intellij screen shot. Helped me solve the issue! – GhostCat Apr 23 '18 at 08:48
  • 6
    I tried this with Mockito 2.18.3 and I also tried using `testImplementation "org.mockito:mockito-inline:$mockitoVersion"` but I'm still getting this error, any idea why? – Franco May 31 '18 at 05:52
  • It might be worth noticing that this caused issues for me when I added it. It seems as if this did something with the debug info in both eclipse and IDEA Intellij when I tried to debug some test cases. There was problems in setting breakpoints in some classes and the 'this' was not readable in debug mode. I used mockito 2.21.0. Just writing this in case someone else get the same problem. – patrik Sep 06 '18 at 13:51
  • @tim I'm crying, I would like to give you more than one 'up' :D (yes, it worked to me!) – marco May 15 '19 at 08:18
  • How do you make it work in an instrumented test scenario? I cannot find my way around to make it work – Camarero Jan 24 '20 at 13:47
  • If I understand https://github.com/mockito/mockito/releases/tag/v5.0.0 correctly, this is the default beginning with mockito-5. – Sören Jan 23 '23 at 21:36
36

I couldn't get it working with the configuration file either; however, the Mockito team is so kind and also provides a pre-configured Mockito artifact that requires no configuration in the target project.

As a convenience, the Mockito team provides an artifact where this mock maker is preconfigured. Instead of using the mockito-core artifact, include the mockito-inline artifact in your project. Note that this artifact is likely to be discontinued once mocking of final classes and methods gets integrated into the default mock maker.

So, if you use Gradle and want to test your Kotlin code, just add this to your project's dependencies:

testCompile 'org.mockito:mockito-inline:2.8.9'
testCompile('com.nhaarman:mockito-kotlin:1.5.0') {
    exclude group: 'org.jetbrains.kotlin'
    exclude group: 'org.mockito'
}
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
Thomas Keller
  • 5,933
  • 6
  • 48
  • 80
10

Well, I found what's wrong here, it maybe useful for other people. My project tree is wrong, I put the org.mockito.plugins.MockMaker in a directory "mockito-extension" directly in "src". This is my tree now:

  • projet
    • src
      • com.packagePath.myPackage
        • myClass
      • mockito-extensions
        • org.mockito.plugins.MockMaker
  • test
    • com.packagePath.myPackage
      • myClassToTest
Ptiseb
  • 795
  • 1
  • 7
  • 19
5

You seem to have had a classpath issue, just like I did.

Your previous setup would have also worked, but it seems like

project/test/resources

was not in your classpath.

I had the same issue when I tried to run this with IntelliJ. I simply marked the resources directory as a Test Resources Root and it worked fine. Praise the gods of Mockito!

Thomas Keller
  • 5,933
  • 6
  • 48
  • 80
Somaiah Kumbera
  • 7,063
  • 4
  • 43
  • 44
5

I had the same issue that you described. For me, the solution was to create a file named org.mockito.plugins.MockMaker in /test/java/resources/mockito-extensions/ directory and write the following line: mock-maker-inline.

So MockMaker is actually the file extension (no txt, properties or any other extension needed).

exody
  • 81
  • 1
  • 5
  • Thanks so much this worked for me. It was unexplainable how my test ran successfully without this mockito-extensions fix, but my test stopped working. I added this extensions and now it works again. Cheers! – vikingsteve Sep 01 '22 at 12:46
1

I also encountered the same issue.

This worked for me: How to use the Mockito's inline mock maker: Option 2

Before Mockito can be used for mocking final classes and methods, it needs to be configured. Based on your screenshot of your project tree, it seems that the location of MockMaker file is incorrect.

Create (if the file still does not exist) or update MockMaker file in the path below

src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker

... and add this line mock-maker-inline.

willow
  • 33
  • 5
0

If you have multiple modules in project check out if they also have some references to Mockito. For me the problem was deprecated and unnecessary definition in some other small and forgotten library module:

testCompile 'org.mockito:mockito-all:1.10.19'

Removing this unnecessary declaration solved the problem for me

KaMyLL
  • 969
  • 1
  • 7
  • 13
0

After following configuration instruction, I still wasn't able to get it working.

For me it was due to JDK I was using. After switching to a different one (different provider) the solution with org.mockito.plugins.MockMaker file worked.

I went from JDK with Hotswap agent (trava-jdk-11-dcevm / dcevm-11.0.11+1) to Eclipse adoptOpenJDK (temurin-11.0.14).

-1

This solution worked for me: Instead of

testCompile "org.mockito:mockito-android:2.9.0"

in the gradle file, replace it with

testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.9.0' 

and it would work.

S.Javed
  • 383
  • 3
  • 8
  • 4
    to be clear, the difference is the different package. hes changed from the artifact `mockito-android` to the artifact `mockito-inline`. It does not matter if you use the single-compact-string form (`"group:artifact:version"`) or the explicit form (`group: 'group', name: 'artifact', version: 'version'`) of the dependency. Between those there is no difference. – Groostav Apr 26 '19 at 04:18
  • This does not work for me. I always get a `java.lang.ExceptionInInitializerError`. – Daniel Connelly Jul 08 '20 at 03:53