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:
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.