Final method mocking

JavaUnit TestingTestingMockingMockito

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

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.

Solution 4 - Java

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

Solution 5 - Java

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.

Solution 6 - Java

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());

}

Solution 7 - Java

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.

Solution 8 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStan KurilinView Question on Stackoverflow
Solution 1 - Javamatt bView Answer on Stackoverflow
Solution 2 - JavaiweinView Answer on Stackoverflow
Solution 3 - JavaJustin RoweView Answer on Stackoverflow
Solution 4 - JavaWindRiderView Answer on Stackoverflow
Solution 5 - JavaCypress FrankenfeldView Answer on Stackoverflow
Solution 6 - JavaMurtuza MithaiwalaView Answer on Stackoverflow
Solution 7 - JavaBill KView Answer on Stackoverflow
Solution 8 - JavaSanjay BharwaniView Answer on Stackoverflow