11

My development team has started to use Mockito and have classes that have been defined as 'final'. I've read in Effective Java by Joshua Bloch and in the SO thread When to use final that all classes should use the final modifier. There have been some disagreement in the thread, but I do agree with the idea of forcing class composition unless inheritance makes sense.

What should I do when I want to test classes using a testing framework like Mockito that requires classes to not have the 'final' modifier? I'm hoping someone else has encountered similar issues during their development. What resolutions did your development team arrive on?

There are two obvious answers such as using JMock or remove the 'final' modifier on the classes we want to test, but we want to stick with one external testing framework (besides JUnit) and it may be hard to convince other developers to remove the 'final' modifier.

Thanks.

Community
  • 1
  • 1
austen
  • 3,314
  • 3
  • 25
  • 26
  • 4
    Making all *classes* `final` certainly isn't a best practice... it's been a while since reading Effective Java, but the consensus of the linked thread certainly doesn't seem to imply that either. You should mark classes `final` to signify there's some reason they shouldn't be extended - if there's no reason, it just adds unneeded complexity - as you have found. Also, if you realize you do need to extend the class somewhere down the road, you have to change the code of the original class to write the new class - violating the Open/Closed principle. – Nate Jan 13 '10 at 03:38

3 Answers3

10

What do you need most:

  1. The ability to make sure that somebody doesn't inherit from your class, OR
  2. The ability to make sure that your code is testable using your mocking framework of choice?

Generally, I believe that you don't need to enforce (1). For me, testability (2), is far more important. What fits your situation best?

Kaleb Pederson
  • 45,767
  • 19
  • 102
  • 147
  • Testability is far more important IMHO and I believe it fits our situation. – austen Jan 13 '10 at 19:28
  • 1
    There is no need to sacrifice design for the sake of "testability". You can have both, by simply using the right tool for the job. In this case, use one of the Java mocking tools which can mock final methods and classes: JMockit (my own tool), or PowerMock (which supports the Mockito API, so you don't have to fully rewrite existing tests). – Rogério Jun 08 '10 at 18:19
4

If you want your classes to be final you can have them implement interfaces. The interfaces are mockable.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
4

As already mentioned in the other answer you can make your final classes to implement interface(s) and in your tests mock the interface(s).

This is one of the benefit of using Mock objects; in scenarios like this they make you to think about how the code can be better organized. If your code base has lot of reference to final classes (thus binding to concrete implementation) it violates the OO principle of "programming to an interface" and the need of better testability would help you to think of refactoring to eliminate dependency on concrete implementations.

This paper on usage of Mock Objects Endo-testing: Unit Testing with Mock Objects has a section (4.4) titled Interface discovery that explains how mock objects help in discovering the interfaces.

sateesh
  • 27,947
  • 7
  • 36
  • 45
  • I like the idea of interface discovery. – austen Jan 13 '10 at 19:27
  • 3
    When I write code that uses a final class and this class does not implement a separate interface, I am *not* violating the "program to an interface, not an implementation" GoF principle. The principle does *not* require that every class implement a separate interface. Other parts of the GoF book make this clear, for those willing to actually read it. – Rogério Jun 08 '10 at 18:24