Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid final methods when unit testing with Mockito? [closed]

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.

like image 238
myartsev Avatar asked Jun 25 '26 04:06

myartsev


1 Answers

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.

like image 145
Jeff Bowman Avatar answered Jun 27 '26 18:06

Jeff Bowman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!