Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock final class with Mockito 2

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!

like image 969
Ptiseb Avatar asked Dec 05 '16 16:12

Ptiseb


People also ask

Can we mock final class using Mockito?

You cannot mock a final class with Mockito, as you can't do it by yourself.

What is MockMaker?

MockMaker is an extension point that makes it possible to use custom dynamic proxies and avoid using the default byte-buddy/asm/objenesis implementation. For example, the android users can use a MockMaker that can work with Dalvik virtual machine and hence bring Mockito to android apps developers.

How do you use a mock maker inline?

Option 2: Adding a file to enable the Mock maker inlineCreate a resources directory in your test directory if you do not have one. In resources create the directory mockito-extensions and in that directory the file org. mockito. plugins.


1 Answers

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

like image 144
timr Avatar answered Sep 22 '22 17:09

timr