75

I need mock some class with final method using mockito. I have wrote something like this

@Test
public void test() {
    B b = mock(B.class);
    doReturn("bar called").when(b).bar();   
    assertEquals("must be \"overrided\"", "bar called", b.bar());
    //bla-bla
}


class B {
    public final String bar() {
        return "fail";
    }
}

But it fails. I tried some "hack" and it works.

   @Test
   public void hackTest() {
        class NewB extends B {
            public String barForTest() {
                return bar();
            }
        }
        NewB b = mock(NewB.class);
        doReturn("bar called").when(b).barForTest();
        assertEquals("must be \"overrided\"", "bar called", b.barForTest());
    }

It works, but "smells".

So, Where is the right way?

Thanks.

Stan Kurilin
  • 15,614
  • 21
  • 81
  • 132
  • 8
    The ideal is not to need to mock final methods, of course. You haven't told us anything about why you're trying to do this. I normally try hard to keep my dependencies to interfaces... is there any way you could use an interface which proxies to the real class (assuming you can't change the class itself)? – Jon Skeet Sep 25 '10 at 12:31
  • 1
    This class from some legacy code. – Stan Kurilin Sep 25 '10 at 12:35
  • 1
    Do you have no option to modify it? Or to proxy to it via another class which implements an interface? – Jon Skeet Sep 25 '10 at 12:41
  • 2
    @Jon Skeet: I can't modify it. You see, it's library (SWT). There are interface IFigure and implementation - Figure. But IFigure doen't contains getLocation(). – Stan Kurilin Sep 25 '10 at 12:47
  • @Jon Skeet: sorry, not SWT. It's org.eclipse.draw2d. – Stan Kurilin Sep 25 '10 at 12:53

9 Answers9

37

From the Mockito FAQ:

What are the limitations of Mockito

  • Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
Chriki
  • 15,638
  • 3
  • 51
  • 66
matt b
  • 138,234
  • 66
  • 282
  • 345
  • 3
    Now that is only listed under *Mockito 1.x Specific Limitations* https://github.com/mockito/mockito/wiki/FAQ#mockito-1x-specific-limitations. Perhaps you can mock final methods in Mockito 2.x? – Cypress Frankenfeld Dec 17 '18 at 22:42
  • 3
    Yes, I just checked and you can now mock final methods in Mockito 2.x. I added how to do so in an answer: https://stackoverflow.com/a/53837478/382892 – Cypress Frankenfeld Dec 18 '18 at 16:40
36

There is no support for mocking final methods in Mockito.

As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)

A comparison between Mockito and PowerMock will explain things in detail.

iwein
  • 25,788
  • 10
  • 70
  • 111
23

You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class

@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)

@PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.

athspk
  • 6,722
  • 7
  • 37
  • 51
Justin Rowe
  • 2,356
  • 1
  • 20
  • 15
  • 3
    This doesn't work for me. Added as adviced but still getting `NullPointerException` in the same way when not using the `@RunWith` and `@PrepareForTest`. Seems the class hasn't been intrumented for some reason. – Jan Zyka Nov 25 '15 at 10:29
  • You should then mock with `PowerMockito.mock`, not `Mockito.mock`. – Cedric Reichenbach Jul 25 '18 at 14:25
  • Mockito now supports final method mocking in Mockito 2.x https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods – Cypress Frankenfeld Feb 05 '19 at 18:15
17

Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here: https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

WindRider
  • 11,958
  • 6
  • 50
  • 57
  • Thanks for this. Do you happen to know what the current state of `verify`ing `final` methods is? Obviously I had a look in that page but it didn't seem to say anything... – mike rodent Dec 02 '16 at 19:56
  • I'm not sure. Check out this: http://stackoverflow.com/questions/14292863/how-to-mock-a-final-class-with-mockito/40018295#40018295 – WindRider Dec 04 '16 at 13:38
13

Mockito 2.x now supports final method and final class stubbing.

From the docs:

Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:

mock-maker-inline

After you create this file you 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.

Community
  • 1
  • 1
Cypress Frankenfeld
  • 2,317
  • 2
  • 28
  • 40
  • 2
    I tried this approach with _SpringRunner_ and worked for the specific use case I wanted, but making all mocks in the project _inlined_ broke multiple tests in the project, all of them run with _MockitoJUnitRunner_. I could provide more details if somebody wanted to investigate further. For now I'll wait until that functionality is incorporated into the Mockito code base without altering all the mocks of the project. – vmaldosan Feb 26 '19 at 12:52
  • Note that this method doesn't work for Android. https://github.com/mockito/mockito/issues/1173 – ThomasW Feb 18 '20 at 08:04
  • [alternative method, mockito-inline](https://stackoverflow.com/a/44422008/185123) – spottedmahn Feb 29 '20 at 03:59
  • Be warned, this may slow down your tests – Snekse Mar 04 '20 at 20:08
3

Assuming that B class is as below:

class B {
    private String barValue;
    public final String bar() {
        return barValue;
    }
    public void final setBar(String barValue) {
        this.barValue = barValue;
    }
}

There is a better way to do this without using PowerMockito framework. You can create a SPY for your class and can mock your final method. Below is the way to do it:

@Test
public void test() {

    B b  = new B();
    b.setBar("bar called") //This should the expected output:final_method_bar()
    B spyB = Mockito.spy(b);
    assertEquals("bar called", spyB.bar());

}
1

Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.

So, in order to do that,

Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below

mock-maker-inline

Once done, you can use the mockito's when method to mock the behaviour like any other regular method.

See detailed examples here

Sanjay Bharwani
  • 3,317
  • 34
  • 31
0

I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.

I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.

I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.

In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.

Kirby
  • 15,127
  • 10
  • 89
  • 104
Bill K
  • 62,186
  • 18
  • 105
  • 157
0

In case you don't want to use mock-maker-inline or PowerMock (like in my case where usage of these caused some other tests of the monolith app to fail), you can do this:

  1. Wrap the method calls of final class or final methods in protected methods inside the class under test.
  2. @Spy the class you want to test and mock the protected methods you created in #1

Refer these for mocking methods of class under test : mock methods in same class and How to mock another method in the same class which is being tested?

Smile
  • 3,832
  • 3
  • 25
  • 39