Avoid final methods when unit testing with Mockito?

java, mockito, unit-testing

Solution

`final` methods absolutely are not bad practice in general: They convey a specific piece of information about the behavior and semantics of a method—namely, that anyone calling that method will get exactly that implementation. That's exactly the property you're trying to subvert through mocking, because you're overriding the final implementation through a (dynamically-generated) subclass to perform the stubbed behavior instead.

To that end, if you have an implementation you control that you're trying to replace in tests with a stub, it probably shouldn't be `final`, because you're treating it as a non-`final` method yourself in your test. Your test is another user of your component, and one you can design for accordingly.

In implementations you don't control, such as third-party libraries, PowerMock is a generally-accepted solution for mocking constructors as well as `private`, `static` and `final` methods, potentially in `final` classes. PowerMock does come with some hazards, though:

- There is additional complexity of mocking: PowerMock works through a special classloader that rewrites the classes themselves, rather than through Java's OOP method dispatch, so you have to explicitly list the classes calling the `final` and `static` methods you're stubbing so Powermock can replace those calls.

- There is additional risk in mocking classes you don't control, if you do so: You may be left in a bad position if the API or implementation changes in an incompatible way.

- By violating the semantics of the `final` modifier, it may make your code harder to read—you're declaring the method to have one well-defined predictable behavior and then working around your own declaration.

In terms of "best practices", the real best practice is the OOP tenet jgitter alludes to above: "Program to interfaces, not implementations." By relying on explicit interfaces:

- ...you make extremely clear the contract of the object you're interacting with.

- ...you are free to stub and verify methods without involving implementation details like `final` methods, methods not visible to the test, or methods in superclasses not visible to the test. Final methods are particularly insidious because Mockito can't warn you about them.

- ...you make it easy to change out implementations, including improved future implementations, Mockito-generated mocks as you have here, or full fake implementations for testing.

That said, the ease with which Mockito stubs concrete classes makes it a tempting option, but be aware that the simplest semantically-correct answer may be to just remove `final` from a particular method that needs stubbing.

Problem

Mockito does not allow mocking of final methods. Is it considered bad practice to have final methods in your code? And why? I don't want to change implementation details just to make test code work, but, often times testing frameworks have these rules to encourage better coding practices.

Original source

Related problems