Reputation: 15792
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.
Upvotes: 78
Views: 97870
Reputation: 4088
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:
@Spy
the class you want to test and mock the protected methods you created in #1Refer 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?
Upvotes: 0
Reputation: 4759
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
Upvotes: 2
Reputation: 62769
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.
Upvotes: 0
Reputation: 2527
Mockito 2.x now supports final method and final class stubbing.
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.
Upvotes: 16
Reputation: 31
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());
}
Upvotes: 3
Reputation: 12308
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
Upvotes: 18
Reputation: 26161
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.
Upvotes: 37
Reputation: 139931
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.
Upvotes: 37
Reputation: 2446
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.
Upvotes: 23